diff options
author | Olof Johansson <olof@lixom.net> | 2013-11-15 15:17:59 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-11-15 15:17:59 -0800 |
commit | 6886059f2ef5d62c73e87a905e84fa4f87d56074 (patch) | |
tree | dfe6e1611d7c50057df52db7b55eafbfb8e33a93 /drivers | |
parent | ca439c9b983ffa14e9eae6030e3ee80ad039388f (diff) | |
parent | 26273e02a0cf18eb72416559310d3294390a9024 (diff) |
Merge tag 'omap-for-v3.13/fixes-for-merge-window-take2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into fixes
Few clock fixes, a runtime PM fix, and pinctrl-single fix along
with few other fixes that popped up during the merge window.
* tag 'omap-for-v3.13/fixes-for-merge-window-take2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
ARM: OMAP2+: Fix build for dra7xx without omap4 and 5
ARM: OMAP2+: omap_device: maintain sane runtime pm status around suspend/resume
doc: devicetree: Add bindings documentation for omap-des driver
ARM: dts: doc: Document missing compatible property for omap-sham driver
ARM: OMAP3: Beagle: fix return value check in beagle_opp_init()
ARM: OMAP: devicetree: fix SPI node compatible property syntax items
pinctrl: single: call pcs_soc->rearm() whenever IRQ mask is changed
ARM: OMAP2+: smsc911x: fix return value check in gpmc_smsc911x_init()
+ sync with newer trunk
Diffstat (limited to 'drivers')
432 files changed, 22120 insertions, 5526 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 6efe2ac6902..e11faae81ed 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -372,4 +372,25 @@ config ACPI_BGRT source "drivers/acpi/apei/Kconfig" +config ACPI_EXTLOG + tristate "Extended Error Log support" + depends on X86_MCE && X86_LOCAL_APIC + select EFI + select UEFI_CPER + default n + help + Certain usages such as Predictive Failure Analysis (PFA) require + more information about the error than what can be described in + processor machine check banks. Most server processors log + additional information about the error in processor uncore + registers. Since the addresses and layout of these registers vary + widely from one processor to another, system software cannot + readily make use of them. To complicate matters further, some of + the additional error information cannot be constructed without + detailed knowledge about platform topology. + + Enhanced MCA Logging allows firmware to provide additional error + information to system software, synchronous with MCE or CMCI. This + driver adds support for that functionality. + endif # ACPI diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index cdaf68b58b0..bce34afadcd 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -82,3 +82,5 @@ processor-$(CONFIG_CPU_FREQ) += processor_perflib.o obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o obj-$(CONFIG_ACPI_APEI) += apei/ + +obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c new file mode 100644 index 00000000000..a6869e110ce --- /dev/null +++ b/drivers/acpi/acpi_extlog.c @@ -0,0 +1,327 @@ +/* + * Extended Error Log driver + * + * Copyright (C) 2013 Intel Corp. + * Author: Chen, Gong <gong.chen@intel.com> + * + * This file is licensed under GPLv2. + */ + +#include <linux/module.h> +#include <linux/acpi.h> +#include <acpi/acpi_bus.h> +#include <linux/cper.h> +#include <linux/ratelimit.h> +#include <asm/cpu.h> +#include <asm/mce.h> + +#include "apei/apei-internal.h" + +#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ + +#define EXTLOG_DSM_REV 0x0 +#define EXTLOG_FN_QUERY 0x0 +#define EXTLOG_FN_ADDR 0x1 + +#define FLAG_OS_OPTIN BIT(0) +#define EXTLOG_QUERY_L1_EXIST BIT(1) +#define ELOG_ENTRY_VALID (1ULL<<63) +#define ELOG_ENTRY_LEN 0x1000 + +#define EMCA_BUG \ + "Can not request iomem region <0x%016llx-0x%016llx> - eMCA disabled\n" + +struct extlog_l1_head { + u32 ver; /* Header Version */ + u32 hdr_len; /* Header Length */ + u64 total_len; /* entire L1 Directory length including this header */ + u64 elog_base; /* MCA Error Log Directory base address */ + u64 elog_len; /* MCA Error Log Directory length */ + u32 flags; /* bit 0 - OS/VMM Opt-in */ + u8 rev0[12]; + u32 entries; /* Valid L1 Directory entries per logical processor */ + u8 rev1[12]; +}; + +static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; + +/* L1 table related physical address */ +static u64 elog_base; +static size_t elog_size; +static u64 l1_dirbase; +static size_t l1_size; + +/* L1 table related virtual address */ +static void __iomem *extlog_l1_addr; +static void __iomem *elog_addr; + +static void *elog_buf; + +static u64 *l1_entry_base; +static u32 l1_percpu_entry; + +#define ELOG_IDX(cpu, bank) \ + (cpu_physical_id(cpu) * l1_percpu_entry + (bank)) + +#define ELOG_ENTRY_DATA(idx) \ + (*(l1_entry_base + (idx))) + +#define ELOG_ENTRY_ADDR(phyaddr) \ + (phyaddr - elog_base + (u8 *)elog_addr) + +static struct acpi_generic_status *extlog_elog_entry_check(int cpu, int bank) +{ + int idx; + u64 data; + struct acpi_generic_status *estatus; + + WARN_ON(cpu < 0); + idx = ELOG_IDX(cpu, bank); + data = ELOG_ENTRY_DATA(idx); + if ((data & ELOG_ENTRY_VALID) == 0) + return NULL; + + data &= EXT_ELOG_ENTRY_MASK; + estatus = (struct acpi_generic_status *)ELOG_ENTRY_ADDR(data); + + /* if no valid data in elog entry, just return */ + if (estatus->block_status == 0) + return NULL; + + return estatus; +} + +static void __print_extlog_rcd(const char *pfx, + struct acpi_generic_status *estatus, int cpu) +{ + static atomic_t seqno; + unsigned int curr_seqno; + char pfx_seq[64]; + + if (!pfx) { + if (estatus->error_severity <= CPER_SEV_CORRECTED) + pfx = KERN_INFO; + else + pfx = KERN_ERR; + } + curr_seqno = atomic_inc_return(&seqno); + snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx, curr_seqno); + printk("%s""Hardware error detected on CPU%d\n", pfx_seq, cpu); + cper_estatus_print(pfx_seq, estatus); +} + +static int print_extlog_rcd(const char *pfx, + struct acpi_generic_status *estatus, int cpu) +{ + /* Not more than 2 messages every 5 seconds */ + static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); + static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2); + struct ratelimit_state *ratelimit; + + if (estatus->error_severity == CPER_SEV_CORRECTED || + (estatus->error_severity == CPER_SEV_INFORMATIONAL)) + ratelimit = &ratelimit_corrected; + else + ratelimit = &ratelimit_uncorrected; + if (__ratelimit(ratelimit)) { + __print_extlog_rcd(pfx, estatus, cpu); + return 0; + } + + return 1; +} + +static int extlog_print(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct mce *mce = (struct mce *)data; + int bank = mce->bank; + int cpu = mce->extcpu; + struct acpi_generic_status *estatus; + int rc; + + estatus = extlog_elog_entry_check(cpu, bank); + if (estatus == NULL) + return NOTIFY_DONE; + + memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN); + /* clear record status to enable BIOS to update it again */ + estatus->block_status = 0; + + rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); + + return NOTIFY_DONE; +} + +static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_object_list input; + union acpi_object params[4], *obj; + u8 uuid[16]; + int i; + + acpi_str_to_uuid(extlog_dsm_uuid, uuid); + input.count = 4; + input.pointer = params; + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = 16; + params[0].buffer.pointer = uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = rev; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) + return -1; + + *ret = 0; + obj = (union acpi_object *)buf.pointer; + if (obj->type == ACPI_TYPE_INTEGER) { + *ret = obj->integer.value; + } else if (obj->type == ACPI_TYPE_BUFFER) { + if (obj->buffer.length <= 8) { + for (i = 0; i < obj->buffer.length; i++) + *ret |= (obj->buffer.pointer[i] << (i * 8)); + } + } + kfree(buf.pointer); + + return 0; +} + +static bool extlog_get_l1addr(void) +{ + acpi_handle handle; + u64 ret; + + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) + return false; + + if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) || + !(ret & EXTLOG_QUERY_L1_EXIST)) + return false; + + if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) + return false; + + l1_dirbase = ret; + /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ + if (l1_dirbase & ((1 << 12) - 1)) { + pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", + l1_dirbase); + return false; + } + + return true; +} +static struct notifier_block extlog_mce_dec = { + .notifier_call = extlog_print, +}; + +static int __init extlog_init(void) +{ + struct extlog_l1_head *l1_head; + void __iomem *extlog_l1_hdr; + size_t l1_hdr_size; + struct resource *r; + u64 cap; + int rc; + + rc = -ENODEV; + + rdmsrl(MSR_IA32_MCG_CAP, cap); + if (!(cap & MCG_ELOG_P)) + return rc; + + if (!extlog_get_l1addr()) + return rc; + + rc = -EINVAL; + /* get L1 header to fetch necessary information */ + l1_hdr_size = sizeof(struct extlog_l1_head); + r = request_mem_region(l1_dirbase, l1_hdr_size, "L1 DIR HDR"); + if (!r) { + pr_warn(FW_BUG EMCA_BUG, + (unsigned long long)l1_dirbase, + (unsigned long long)l1_dirbase + l1_hdr_size); + goto err; + } + + extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size); + l1_head = (struct extlog_l1_head *)extlog_l1_hdr; + l1_size = l1_head->total_len; + l1_percpu_entry = l1_head->entries; + elog_base = l1_head->elog_base; + elog_size = l1_head->elog_len; + acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size); + release_mem_region(l1_dirbase, l1_hdr_size); + + /* remap L1 header again based on completed information */ + r = request_mem_region(l1_dirbase, l1_size, "L1 Table"); + if (!r) { + pr_warn(FW_BUG EMCA_BUG, + (unsigned long long)l1_dirbase, + (unsigned long long)l1_dirbase + l1_size); + goto err; + } + extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size); + l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size); + + /* remap elog table */ + r = request_mem_region(elog_base, elog_size, "Elog Table"); + if (!r) { + pr_warn(FW_BUG EMCA_BUG, + (unsigned long long)elog_base, + (unsigned long long)elog_base + elog_size); + goto err_release_l1_dir; + } + elog_addr = acpi_os_map_memory(elog_base, elog_size); + + rc = -ENOMEM; + /* allocate buffer to save elog record */ + elog_buf = kmalloc(ELOG_ENTRY_LEN, GFP_KERNEL); + if (elog_buf == NULL) + goto err_release_elog; + + mce_register_decode_chain(&extlog_mce_dec); + /* enable OS to be involved to take over management from BIOS */ + ((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN; + + return 0; + +err_release_elog: + if (elog_addr) + acpi_os_unmap_memory(elog_addr, elog_size); + release_mem_region(elog_base, elog_size); +err_release_l1_dir: + if (extlog_l1_addr) + acpi_os_unmap_memory(extlog_l1_addr, l1_size); + release_mem_region(l1_dirbase, l1_size); +err: + pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n"); + return rc; +} + +static void __exit extlog_exit(void) +{ + mce_unregister_decode_chain(&extlog_mce_dec); + ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; + if (extlog_l1_addr) + acpi_os_unmap_memory(extlog_l1_addr, l1_size); + if (elog_addr) + acpi_os_unmap_memory(elog_addr, elog_size); + release_mem_region(elog_base, elog_size); + release_mem_region(l1_dirbase, l1_size); + kfree(elog_buf); +} + +module_init(extlog_init); +module_exit(extlog_exit); + +MODULE_AUTHOR("Chen, Gong <gong.chen@intel.com>"); +MODULE_DESCRIPTION("Extended MCA Error Log Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index f0c1ce95a0e..786294bb682 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -2,6 +2,8 @@ config ACPI_APEI bool "ACPI Platform Error Interface (APEI)" select MISC_FILESYSTEMS select PSTORE + select EFI + select UEFI_CPER depends on X86 help APEI allows to report errors (for example from the chipset) diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile index d1d1bc0a4ee..5d575a95594 100644 --- a/drivers/acpi/apei/Makefile +++ b/drivers/acpi/apei/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o -apei-y := apei-base.o hest.o cper.o erst.o +apei-y := apei-base.o hest.o erst.o diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index f220d642136..21ba34a7388 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -122,11 +122,11 @@ struct dentry; struct dentry *apei_get_debugfs_dir(void); #define apei_estatus_for_each_section(estatus, section) \ - for (section = (struct acpi_hest_generic_data *)(estatus + 1); \ + for (section = (struct acpi_generic_data *)(estatus + 1); \ (void *)section - (void *)estatus < estatus->data_length; \ section = (void *)(section+1) + section->error_data_length) -static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus) +static inline u32 cper_estatus_len(struct acpi_generic_status *estatus) { if (estatus->raw_data_length) return estatus->raw_data_offset + \ @@ -135,10 +135,10 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus) return sizeof(*estatus) + estatus->data_length; } -void apei_estatus_print(const char *pfx, - const struct acpi_hest_generic_status *estatus); -int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); -int apei_estatus_check(const struct acpi_hest_generic_status *estatus); +void cper_estatus_print(const char *pfx, + const struct acpi_generic_status *estatus); +int cper_estatus_check_header(const struct acpi_generic_status *estatus); +int cper_estatus_check(const struct acpi_generic_status *estatus); int apei_osc_setup(void); #endif diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 8ec37bbdd69..a30bc313787 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -75,13 +75,13 @@ #define GHES_ESTATUS_CACHE_LEN(estatus_len) \ (sizeof(struct ghes_estatus_cache) + (estatus_len)) #define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ - ((struct acpi_hest_generic_status *) \ + ((struct acpi_generic_status *) \ ((struct ghes_estatus_cache *)(estatus_cache) + 1)) #define GHES_ESTATUS_NODE_LEN(estatus_len) \ (sizeof(struct ghes_estatus_node) + (estatus_len)) -#define GHES_ESTATUS_FROM_NODE(estatus_node) \ - ((struct acpi_hest_generic_status *) \ +#define GHES_ESTATUS_FROM_NODE(estatus_node) \ + ((struct acpi_generic_status *) \ ((struct ghes_estatus_node *)(estatus_node) + 1)) bool ghes_disable; @@ -378,17 +378,17 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) ghes->flags |= GHES_TO_CLEAR; rc = -EIO; - len = apei_estatus_len(ghes->estatus); + len = cper_estatus_len(ghes->estatus); if (len < sizeof(*ghes->estatus)) goto err_read_block; if (len > ghes->generic->error_block_length) goto err_read_block; - if (apei_estatus_check_header(ghes->estatus)) + if (cper_estatus_check_header(ghes->estatus)) goto err_read_block; ghes_copy_tofrom_phys(ghes->estatus + 1, buf_paddr + sizeof(*ghes->estatus), len - sizeof(*ghes->estatus), 1); - if (apei_estatus_check(ghes->estatus)) + if (cper_estatus_check(ghes->estatus)) goto err_read_block; rc = 0; @@ -409,7 +409,7 @@ static void ghes_clear_estatus(struct ghes *ghes) ghes->flags &= ~GHES_TO_CLEAR; } -static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev) +static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) { #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE unsigned long pfn; @@ -419,7 +419,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int if (sec_sev == GHES_SEV_CORRECTED && (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && - (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) { + (mem_err->validation_bits & CPER_MEM_VALID_PA)) { pfn = mem_err->physical_addr >> PAGE_SHIFT; if (pfn_valid(pfn)) memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); @@ -430,7 +430,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int } if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE && - mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { + mem_err->validation_bits & CPER_MEM_VALID_PA) { pfn = mem_err->physical_addr >> PAGE_SHIFT; memory_failure_queue(pfn, 0, 0); } @@ -438,10 +438,10 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int } static void ghes_do_proc(struct ghes *ghes, - const struct acpi_hest_generic_status *estatus) + const struct acpi_generic_status *estatus) { int sev, sec_sev; - struct acpi_hest_generic_data *gdata; + struct acpi_generic_data *gdata; sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { @@ -496,7 +496,7 @@ static void ghes_do_proc(struct ghes *ghes, static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, - const struct acpi_hest_generic_status *estatus) + const struct acpi_generic_status *estatus) { static atomic_t seqno; unsigned int curr_seqno; @@ -513,12 +513,12 @@ static void __ghes_print_estatus(const char *pfx, snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", pfx_seq, generic->header.source_id); - apei_estatus_print(pfx_seq, estatus); + cper_estatus_print(pfx_seq, estatus); } static int ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, - const struct acpi_hest_generic_status *estatus) + const struct acpi_generic_status *estatus) { /* Not more than 2 messages every 5 seconds */ static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); @@ -540,15 +540,15 @@ static int ghes_print_estatus(const char *pfx, * GHES error status reporting throttle, to report more kinds of * errors, instead of just most frequently occurred errors. */ -static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) +static int ghes_estatus_cached(struct acpi_generic_status *estatus) { u32 len; int i, cached = 0; unsigned long long now; struct ghes_estatus_cache *cache; - struct acpi_hest_generic_status *cache_estatus; + struct acpi_generic_status *cache_estatus; - len = apei_estatus_len(estatus); + len = cper_estatus_len(estatus); rcu_read_lock(); for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { cache = rcu_dereference(ghes_estatus_caches[i]); @@ -571,19 +571,19 @@ static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) static struct ghes_estatus_cache *ghes_estatus_cache_alloc( struct acpi_hest_generic *generic, - struct acpi_hest_generic_status *estatus) + struct acpi_generic_status *estatus) { int alloced; u32 len, cache_len; struct ghes_estatus_cache *cache; - struct acpi_hest_generic_status *cache_estatus; + struct acpi_generic_status *cache_estatus; alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { atomic_dec(&ghes_estatus_cache_alloced); return NULL; } - len = apei_estatus_len(estatus); + len = cper_estatus_len(estatus); cache_len = GHES_ESTATUS_CACHE_LEN(len); cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len); if (!cache) { @@ -603,7 +603,7 @@ static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache) { u32 len; - len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); + len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); len = GHES_ESTATUS_CACHE_LEN(len); gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len); atomic_dec(&ghes_estatus_cache_alloced); @@ -619,7 +619,7 @@ static void ghes_estatus_cache_rcu_free(struct rcu_head *head) static void ghes_estatus_cache_add( struct acpi_hest_generic *generic, - struct acpi_hest_generic_status *estatus) + struct acpi_generic_status *estatus) { int i, slot = -1, count; unsigned long long now, duration, period, max_period = 0; @@ -751,7 +751,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) struct llist_node *llnode, *next; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; - struct acpi_hest_generic_status *estatus; + struct acpi_generic_status *estatus; u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); @@ -765,7 +765,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) estatus_node = llist_entry(llnode, struct ghes_estatus_node, llnode); estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - len = apei_estatus_len(estatus); + len = cper_estatus_len(estatus); node_len = GHES_ESTATUS_NODE_LEN(len); ghes_do_proc(estatus_node->ghes, estatus); if (!ghes_estatus_cached(estatus)) { @@ -784,7 +784,7 @@ static void ghes_print_queued_estatus(void) struct llist_node *llnode; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; - struct acpi_hest_generic_status *estatus; + struct acpi_generic_status *estatus; u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); @@ -797,7 +797,7 @@ static void ghes_print_queued_estatus(void) estatus_node = llist_entry(llnode, struct ghes_estatus_node, llnode); estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - len = apei_estatus_len(estatus); + len = cper_estatus_len(estatus); node_len = GHES_ESTATUS_NODE_LEN(len); generic = estatus_node->generic; ghes_print_estatus(NULL, generic, estatus); @@ -843,7 +843,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG u32 len, node_len; struct ghes_estatus_node *estatus_node; - struct acpi_hest_generic_status *estatus; + struct acpi_generic_status *estatus; #endif if (!(ghes->flags & GHES_TO_CLEAR)) continue; @@ -851,7 +851,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) if (ghes_estatus_cached(ghes->estatus)) goto next; /* Save estatus for further processing in IRQ context */ - len = apei_estatus_len(ghes->estatus); + len = cper_estatus_len(ghes->estatus); node_len = GHES_ESTATUS_NODE_LEN(len); estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len); @@ -923,7 +923,7 @@ static int ghes_probe(struct platform_device *ghes_dev) rc = -EIO; if (generic->error_block_length < - sizeof(struct acpi_hest_generic_status)) { + sizeof(struct acpi_generic_status)) { pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n", generic->error_block_length, generic->header.source_id); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b587ec8257b..e1bd9a18111 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -174,7 +174,7 @@ static void acpi_print_osc_error(acpi_handle handle, printk("\n"); } -static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) +acpi_status acpi_str_to_uuid(char *str, u8 *uuid) { int i; static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, @@ -195,6 +195,7 @@ static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) } return AE_OK; } +EXPORT_SYMBOL_GPL(acpi_str_to_uuid); acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) { diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f98dd00b51a..c7414a545a4 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -119,17 +119,10 @@ static struct dmi_system_id processor_power_dmi_table[] = { */ static void acpi_safe_halt(void) { - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we - * test NEED_RESCHED: - */ - smp_mb(); - if (!need_resched()) { + if (!tif_need_resched()) { safe_halt(); local_irq_disable(); } - current_thread_info()->status |= TS_POLLING; } #ifdef ARCH_APICTIMER_STOPS_ON_C3 @@ -737,6 +730,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; + if (cx->entry_method == ACPI_CSTATE_FFH) { + if (current_set_polling_and_test()) + return -EINVAL; + } + lapic_timer_state_broadcast(pr, cx, 1); acpi_idle_do_entry(cx); @@ -790,18 +788,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(!pr)) return -EINVAL; - if (cx->entry_method != ACPI_CSTATE_FFH) { - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we test - * NEED_RESCHED: - */ - smp_mb(); - - if (unlikely(need_resched())) { - current_thread_info()->status |= TS_POLLING; + if (cx->entry_method == ACPI_CSTATE_FFH) { + if (current_set_polling_and_test()) return -EINVAL; - } } /* @@ -819,9 +808,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, sched_clock_idle_wakeup_event(0); - if (cx->entry_method != ACPI_CSTATE_FFH) - current_thread_info()->status |= TS_POLLING; - lapic_timer_state_broadcast(pr, cx, 0); return index; } @@ -858,18 +844,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, } } - if (cx->entry_method != ACPI_CSTATE_FFH) { - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we test - * NEED_RESCHED: - */ - smp_mb(); - - if (unlikely(need_resched())) { - current_thread_info()->status |= TS_POLLING; + if (cx->entry_method == ACPI_CSTATE_FFH) { + if (current_set_polling_and_test()) return -EINVAL; - } } acpi_unlazy_tlb(smp_processor_id()); @@ -915,9 +892,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, sched_clock_idle_wakeup_event(0); - if (cx->entry_method != ACPI_CSTATE_FFH) - current_thread_info()->status |= TS_POLLING; - lapic_timer_state_broadcast(pr, cx, 0); return index; } diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 2e391730e8b..523524b6802 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -31,6 +31,8 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/libata.h> diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 851bd3f43ac..fb0b40a191c 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -24,6 +24,8 @@ #include <scsi/scsi_cmnd.h> #include <linux/libata.h> #include <asm/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> static unsigned int intr_coalescing_count; diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index f0d30543fcc..4251570610c 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -3,7 +3,7 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_MMIO || REGMAP_IRQ) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) select LZO_COMPRESS select LZO_DECOMPRESS select IRQ_DOMAIN if REGMAP_IRQ @@ -15,6 +15,9 @@ config REGMAP_I2C config REGMAP_SPI tristate +config REGMAP_SPMI + tristate + config REGMAP_MMIO tristate diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index cf129980abd..a7c670b4123 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o +obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f777835d9..33414b1de20 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -44,7 +44,6 @@ struct regmap_format { struct regmap_async { struct list_head list; - struct work_struct cleanup; struct regmap *map; void *work_buf; }; @@ -64,9 +63,11 @@ struct regmap { void *bus_context; const char *name; + bool async; spinlock_t async_lock; wait_queue_head_t async_waitq; struct list_head async_list; + struct list_head async_free; int async_ret; #ifdef CONFIG_DEBUG_FS @@ -179,6 +180,9 @@ struct regmap_field { /* lsb */ unsigned int shift; unsigned int reg; + + unsigned int id_size; + unsigned int id_offset; }; #ifdef CONFIG_DEBUG_FS @@ -218,7 +222,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, int regcache_lookup_reg(struct regmap *map, unsigned int reg); int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async); + const void *val, size_t val_len); void regmap_async_complete_cb(struct regmap_async *async, int ret); diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d6c2d691b6e..d4dd7713481 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -307,6 +307,8 @@ int regcache_sync(struct regmap *map) if (!map->cache_dirty) goto out; + map->async = true; + /* Apply any patch first */ map->cache_bypass = 1; for (i = 0; i < map->patch_regs; i++) { @@ -332,11 +334,15 @@ int regcache_sync(struct regmap *map) map->cache_dirty = false; out: - trace_regcache_sync(map->dev, name, "stop"); /* Restore the bypass state */ + map->async = false; map->cache_bypass = bypass; map->unlock(map->lock_arg); + regmap_async_complete(map); + + trace_regcache_sync(map->dev, name, "stop"); + return ret; } EXPORT_SYMBOL_GPL(regcache_sync); @@ -375,17 +381,23 @@ int regcache_sync_region(struct regmap *map, unsigned int min, if (!map->cache_dirty) goto out; + map->async = true; + if (map->cache_ops->sync) ret = map->cache_ops->sync(map, min, max); else ret = regcache_default_sync(map, min, max); out: - trace_regcache_sync(map->dev, name, "stop region"); /* Restore the bypass state */ map->cache_bypass = bypass; + map->async = false; map->unlock(map->lock_arg); + regmap_async_complete(map); + + trace_regcache_sync(map->dev, name, "stop region"); + return ret; } EXPORT_SYMBOL_GPL(regcache_sync_region); @@ -631,8 +643,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, map->cache_bypass = 1; - ret = _regmap_raw_write(map, base, *data, count * val_bytes, - false); + ret = _regmap_raw_write(map, base, *data, count * val_bytes); map->cache_bypass = 0; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index de11ecaf383..c5471cd6ebb 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -15,10 +15,19 @@ #include <linux/debugfs.h> #include <linux/uaccess.h> #include <linux/device.h> +#include <linux/list.h> #include "internal.h" +struct regmap_debugfs_node { + struct regmap *map; + const char *name; + struct list_head link; +}; + static struct dentry *regmap_debugfs_root; +static LIST_HEAD(regmap_debugfs_early_list); +static DEFINE_MUTEX(regmap_debugfs_early_lock); /* Calculate the length of a fixed format */ static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) @@ -465,6 +474,20 @@ void regmap_debugfs_init(struct regmap *map, const char *name) struct rb_node *next; struct regmap_range_node *range_node; + /* If we don't have the debugfs root yet, postpone init */ + if (!regmap_debugfs_root) { + struct regmap_debugfs_node *node; + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return; + node->map = map; + node->name = name; + mutex_lock(®map_debugfs_early_lock); + list_add(&node->link, ®map_debugfs_early_list); + mutex_unlock(®map_debugfs_early_lock); + return; + } + INIT_LIST_HEAD(&map->debugfs_off_cache); mutex_init(&map->cache_lock); @@ -519,18 +542,42 @@ void regmap_debugfs_init(struct regmap *map, const char *name) void regmap_debugfs_exit(struct regmap *map) { - debugfs_remove_recursive(map->debugfs); - mutex_lock(&map->cache_lock); - regmap_debugfs_free_dump_cache(map); - mutex_unlock(&map->cache_lock); - kfree(map->debugfs_name); + if (map->debugfs) { + debugfs_remove_recursive(map->debugfs); + mutex_lock(&map->cache_lock); + regmap_debugfs_free_dump_cache(map); + mutex_unlock(&map->cache_lock); + kfree(map->debugfs_name); + } else { + struct regmap_debugfs_node *node, *tmp; + + mutex_lock(®map_debugfs_early_lock); + list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, + link) { + if (node->map == map) { + list_del(&node->link); + kfree(node); + } + } + mutex_unlock(®map_debugfs_early_lock); + } } void regmap_debugfs_initcall(void) { + struct regmap_debugfs_node *node, *tmp; + regmap_debugfs_root = debugfs_create_dir("regmap", NULL); if (!regmap_debugfs_root) { pr_warn("regmap: Failed to create debugfs root\n"); return; } + + mutex_lock(®map_debugfs_early_lock); + list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, link) { + regmap_debugfs_init(node->map, node->name); + list_del(&node->link); + kfree(node); + } + mutex_unlock(®map_debugfs_early_lock); } diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index d10456ffd81..763c60d3d27 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -105,6 +105,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) "Failed to sync wakes in %x: %d\n", reg, ret); } + + if (!d->chip->init_ack_masked) + continue; + /* + * Ack all the masked interrupts uncondictionly, + * OR if there is masked interrupt which hasn't been Acked, + * it'll be ignored in irq handler, then may introduce irq storm + */ + if (d->mask_buf[i] && d->chip->ack_base) { + reg = d->chip->ack_base + + (i * map->reg_stride * d->irq_reg_stride); + ret = regmap_write(map, reg, d->mask_buf[i]); + if (ret != 0) + dev_err(d->map->dev, "Failed to ack 0x%x: %d\n", + reg, ret); + } } if (d->chip->runtime_pm) diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 4c506bd940f..37f12ae7aad 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -73,7 +73,8 @@ static int regmap_spi_async_write(void *context, spi_message_init(&async->m); spi_message_add_tail(&async->t[0], &async->m); - spi_message_add_tail(&async->t[1], &async->m); + if (val) + spi_message_add_tail(&async->t[1], &async->m); async->m.complete = regmap_spi_complete; async->m.context = async; diff --git a/drivers/base/regmap/regmap-spmi.c b/drivers/base/regmap/regmap-spmi.c new file mode 100644 index 00000000000..ac2391013db --- /dev/null +++ b/drivers/base/regmap/regmap-spmi.c @@ -0,0 +1,90 @@ +/* + * Register map access API - SPMI support + * + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * Based on regmap-i2c.c: + * Copyright 2011 Wolfson Microelectronics plc + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/regmap.h> +#include <linux/spmi.h> +#include <linux/module.h> +#include <linux/init.h> + +static int regmap_spmi_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + BUG_ON(reg_size != 2); + return spmi_ext_register_readl(context, *(u16 *)reg, + val, val_size); +} + +static int regmap_spmi_gather_write(void *context, + const void *reg, size_t reg_size, + const void *val, size_t val_size) +{ + BUG_ON(reg_size != 2); + return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size); +} + +static int regmap_spmi_write(void *context, const void *data, + size_t count) +{ + BUG_ON(count < 2); + return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2); +} + +static struct regmap_bus regmap_spmi = { + .read = regmap_spmi_read, + .write = regmap_spmi_write, + .gather_write = regmap_spmi_gather_write, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +/** + * regmap_init_spmi(): Initialize register map + * + * @sdev: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer to + * a struct regmap. + */ +struct regmap *regmap_init_spmi(struct spmi_device *sdev, + const struct regmap_config *config) +{ + return regmap_init(&sdev->dev, ®map_spmi, sdev, config); +} +EXPORT_SYMBOL_GPL(regmap_init_spmi); + +/** + * devm_regmap_init_spmi(): Initialise managed register map + * + * @sdev: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap. The regmap will be automatically freed by the + * device management code. + */ +struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev, + const struct regmap_config *config) +{ + return devm_regmap_init(&sdev->dev, ®map_spmi, sdev, config); +} +EXPORT_SYMBOL_GPL(devm_regmap_init_spmi); + +MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a15c50..9c021d9cace 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val); -static void async_cleanup(struct work_struct *work) -{ - struct regmap_async *async = container_of(work, struct regmap_async, - cleanup); - - kfree(async->work_buf); - kfree(async); -} - bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges) @@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev, spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); + INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq); if (config->read_flag_mask || config->write_flag_mask) { @@ -821,6 +813,8 @@ static void regmap_field_init(struct regmap_field *rm_field, rm_field->reg = reg_field.reg; rm_field->shift = reg_field.lsb; rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); + rm_field->id_size = reg_field.id_size; + rm_field->id_offset = reg_field.id_offset; } /** @@ -942,12 +936,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache); */ void regmap_exit(struct regmap *map) { + struct regmap_async *async; + regcache_exit(map); regmap_debugfs_exit(map); regmap_range_exit(map); if (map->bus && map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); + while (!list_empty(&map->async_free)) { + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + list_del(&async->list); + kfree(async->work_buf); + kfree(async); + } kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); @@ -1039,7 +1043,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, } int _regmap_raw_write(struct regmap *map, unsigned int reg, - const void *val, size_t val_len, bool async) + const void *val, size_t val_len) { struct regmap_range_node *range; unsigned long flags; @@ -1091,7 +1095,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, dev_dbg(map->dev, "Writing window %d/%zu\n", win_residue, val_len / map->format.val_bytes); ret = _regmap_raw_write(map, reg, val, win_residue * - map->format.val_bytes, async); + map->format.val_bytes); if (ret != 0) return ret; @@ -1114,49 +1118,72 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, u8[0] |= map->write_flag_mask; - if (async && map->bus->async_write) { - struct regmap_async *async = map->bus->async_alloc(); - if (!async) - return -ENOMEM; + /* + * Essentially all I/O mechanisms will be faster with a single + * buffer to write. Since register syncs often generate raw + * writes of single registers optimise that case. + */ + if (val != work_val && val_len == map->format.val_bytes) { + memcpy(work_val, val, map->format.val_bytes); + val = work_val; + } + + if (map->async && map->bus->async_write) { + struct regmap_async *async; trace_regmap_async_write_start(map->dev, reg, val_len); - async->work_buf = kzalloc(map->format.buf_size, - GFP_KERNEL | GFP_DMA); - if (!async->work_buf) { - kfree(async); - return -ENOMEM; + spin_lock_irqsave(&map->async_lock, flags); + async = list_first_entry_or_null(&map->async_free, + struct regmap_async, + list); + if (async) + list_del(&async->list); + spin_unlock_irqrestore(&map->async_lock, flags); + + if (!async) { + async = map->bus->async_alloc(); + if (!async) + return -ENOMEM; + + async->work_buf = kzalloc(map->format.buf_size, + GFP_KERNEL | GFP_DMA); + if (!async->work_buf) { + kfree(async); + return -ENOMEM; + } } - INIT_WORK(&async->cleanup, async_cleanup); async->map = map; /* If the caller supplied the value we can use it safely. */ memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + map->format.reg_bytes + map->format.val_bytes); - if (val == work_val) - val = async->work_buf + map->format.pad_bytes + - map->format.reg_bytes; spin_lock_irqsave(&map->async_lock, flags); list_add_tail(&async->list, &map->async_list); spin_unlock_irqrestore(&map->async_lock, flags); - ret = map->bus->async_write(map->bus_context, async->work_buf, - map->format.reg_bytes + - map->format.pad_bytes, - val, val_len, async); + if (val != work_val) + ret = map->bus->async_write(map->bus_context, + async->work_buf, + map->format.reg_bytes + + map->format.pad_bytes, + val, val_len, async); + else + ret = map->bus->async_write(map->bus_context, + async->work_buf, + map->format.reg_bytes + + map->format.pad_bytes + + val_len, NULL, 0, async); if (ret != 0) { dev_err(map->dev, "Failed to schedule write: %d\n", ret); spin_lock_irqsave(&map->async_lock, flags); - list_del(&async->list); + list_move(&async->list, &map->async_free); spin_unlock_irqrestore(&map->async_lock, flags); - - kfree(async->work_buf); - kfree(async); } return ret; @@ -1253,7 +1280,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, map->work_buf + map->format.reg_bytes + map->format.pad_bytes, - map->format.val_bytes, false); + map->format.val_bytes); } static inline void *_regmap_map_get_context(struct regmap *map) @@ -1318,6 +1345,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write); /** + * regmap_write_async(): Write a value to a single register asynchronously + * + * @map: Register map to write to + * @reg: Register to write to + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) +{ + int ret; + + if (reg % map->reg_stride) + return -EINVAL; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_write(map, reg, val); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_async); + +/** * regmap_raw_write(): Write raw values to one or more registers * * @map: Register map to write to @@ -1345,7 +1403,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, false); + ret = _regmap_raw_write(map, reg, val, val_len); map->unlock(map->lock_arg); @@ -1369,6 +1427,74 @@ int regmap_field_write(struct regmap_field *field, unsigned int val) } EXPORT_SYMBOL_GPL(regmap_field_write); +/** + * regmap_field_update_bits(): Perform a read/modify/write cycle + * on the register field + * + * @field: Register field to write to + * @mask: Bitmask to change + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) +{ + mask = (mask << field->shift) & field->mask; + + return regmap_update_bits(field->regmap, field->reg, + mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_field_update_bits); + +/** + * regmap_fields_write(): Write a value to a single register field with port ID + * + * @field: Register field to write to + * @id: port ID + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_update_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_write); + +/** + * regmap_fields_update_bits(): Perform a read/modify/write cycle + * on the register field + * + * @field: Register field to write to + * @id: port ID + * @mask: Bitmask to change + * @val: Value to be written + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, + unsigned int mask, unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + mask = (mask << field->shift) & field->mask; + + return regmap_update_bits(field->regmap, + field->reg + (field->id_offset * id), + mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_update_bits); + /* * regmap_bulk_write(): Write multiple registers to the device * @@ -1418,16 +1544,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, */ if (map->use_single_rw) { for (i = 0; i < val_count; i++) { - ret = regmap_raw_write(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); + ret = _regmap_raw_write(map, + reg + (i * map->reg_stride), + val + (i * val_bytes), + val_bytes); if (ret != 0) return ret; } } else { - ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, - false); + ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); } if (val_bytes != 1) @@ -1439,6 +1564,47 @@ out: } EXPORT_SYMBOL_GPL(regmap_bulk_write); +/* + * regmap_multi_reg_write(): Write multiple registers to the device + * + * where the set of register are supplied in any order + * + * @map: Register map to write to + * @regs: Array of structures containing register,value to be written + * @num_regs: Number of registers to write + * + * This function is intended to be used for writing a large block of data + * atomically to the device in single transfer for those I2C client devices + * that implement this alternative block write mode. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs, + int num_regs) +{ + int ret = 0, i; + + for (i = 0; i < num_regs; i++) { + int reg = regs[i].reg; + if (reg % map->reg_stride) + return -EINVAL; + } + + map->lock(map->lock_arg); + + for (i = 0; i < num_regs; i++) { + ret = _regmap_write(map, regs[i].reg, regs[i].def); + if (ret != 0) + goto out; + } +out: + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_multi_reg_write); + /** * regmap_raw_write_async(): Write raw values to one or more registers * asynchronously @@ -1473,7 +1639,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, map->lock(map->lock_arg); - ret = _regmap_raw_write(map, reg, val, val_len, true); + map->async = true; + + ret = _regmap_raw_write(map, reg, val, val_len); + + map->async = false; map->unlock(map->lock_arg); @@ -1677,6 +1847,39 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_field_read); /** + * regmap_fields_read(): Read a value to a single register field with port ID + * + * @field: Register field to read from + * @id: port ID + * @val: Pointer to store read value + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int regmap_fields_read(struct regmap_field *field, unsigned int id, + unsigned int *val) +{ + int ret; + unsigned int reg_val; + + if (id >= field->id_size) + return -EINVAL; + + ret = regmap_read(field->regmap, + field->reg + (field->id_offset * id), + ®_val); + if (ret != 0) + return ret; + + reg_val &= field->mask; + reg_val >>= field->shift; + *val = reg_val; + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_fields_read); + +/** * regmap_bulk_read(): Read multiple registers from the device * * @map: Register map to write to @@ -1788,6 +1991,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_update_bits); /** + * regmap_update_bits_async: Perform a read/modify/write cycle on the register + * map asynchronously + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + bool change; + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, &change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_async); + +/** * regmap_update_bits_check: Perform a read/modify/write cycle on the * register map and report if updated * @@ -1812,6 +2050,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits_check); +/** + * regmap_update_bits_check_async: Perform a read/modify/write cycle on the + * register map asynchronously and report if + * updated + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * @change: Boolean indicating if a write was done + * + * With most buses the read must be done synchronously so this is most + * useful for devices with a cache which do not need to interact with + * the hardware to determine the current register value. + * + * Returns zero for success, a negative number on error. + */ +int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val, + bool *change) +{ + int ret; + + map->lock(map->lock_arg); + + map->async = true; + + ret = _regmap_update_bits(map, reg, mask, val, change); + + map->async = false; + + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); + void regmap_async_complete_cb(struct regmap_async *async, int ret) { struct regmap *map = async->map; @@ -1820,8 +2095,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) trace_regmap_async_io_complete(map->dev); spin_lock(&map->async_lock); - - list_del(&async->list); + list_move(&async->list, &map->async_free); wake = list_empty(&map->async_list); if (ret != 0) @@ -1829,8 +2103,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) spin_unlock(&map->async_lock); - schedule_work(&async->cleanup); - if (wake) wake_up(&map->async_waitq); } @@ -1906,6 +2178,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, bypass = map->cache_bypass; map->cache_bypass = true; + map->async = true; /* Write out first; it's useful to apply even if we fail later. */ for (i = 0; i < num_regs; i++) { @@ -1929,10 +2202,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, } out: + map->async = false; map->cache_bypass = bypass; map->unlock(map->lock_arg); + regmap_async_complete(map); + return ret; } EXPORT_SYMBOL_GPL(regmap_register_patch); diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 0671e45daa5..8fedbc25041 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/fs.h> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 0aa9d91daef..c206de2951f 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -290,6 +290,19 @@ config HW_RANDOM_PSERIES If unsure, say Y. +config HW_RANDOM_POWERNV + tristate "PowerNV Random Number Generator support" + depends on HW_RANDOM && PPC_POWERNV + default HW_RANDOM + ---help--- + This is the driver for Random Number Generator hardware found + in POWER7+ and above machines for PowerNV platform. + + To compile this driver as a module, choose M here: the + module will be called powernv-rng. + + If unsure, say Y. + config HW_RANDOM_EXYNOS tristate "EXYNOS HW random number generator support" depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index bed467c9300..d7d2435ff7f 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o +obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index c6df5b29af0..c66279bb6ef 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -24,6 +24,7 @@ #include <linux/platform_device.h> #include <linux/hw_random.h> #include <linux/delay.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c new file mode 100644 index 00000000000..3f4f6320456 --- /dev/null +++ b/drivers/char/hw_random/powernv-rng.c @@ -0,0 +1,81 @@ +/* + * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/random.h> +#include <linux/hw_random.h> + +static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + unsigned long *buf; + int i, len; + + /* We rely on rng_buffer_size() being >= sizeof(unsigned long) */ + len = max / sizeof(unsigned long); + + buf = (unsigned long *)data; + + for (i = 0; i < len; i++) + powernv_get_random_long(buf++); + + return len * sizeof(unsigned long); +} + +static struct hwrng powernv_hwrng = { + .name = "powernv-rng", + .read = powernv_rng_read, +}; + +static int powernv_rng_remove(struct platform_device *pdev) +{ + hwrng_unregister(&powernv_hwrng); + + return 0; +} + +static int powernv_rng_probe(struct platform_device *pdev) +{ + int rc; + + rc = hwrng_register(&powernv_hwrng); + if (rc) { + /* We only register one device, ignore any others */ + if (rc == -EEXIST) + rc = -ENODEV; + + return rc; + } + + pr_info("Registered powernv hwrng.\n"); + + return 0; +} + +static struct of_device_id powernv_rng_match[] = { + { .compatible = "ibm,power-rng",}, + {}, +}; +MODULE_DEVICE_TABLE(of, powernv_rng_match); + +static struct platform_driver powernv_rng_driver = { + .driver = { + .name = "powernv_rng", + .of_match_table = powernv_rng_match, + }, + .probe = powernv_rng_probe, + .remove = powernv_rng_remove, +}; +module_platform_driver(powernv_rng_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above"); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index 732c330805f..521f76b0934 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/hw_random.h> #include <linux/delay.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index 5f1197929f0..b761459a343 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -17,6 +17,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> #include <linux/module.h> #include <linux/hw_random.h> #include <asm/vio.h> @@ -25,10 +28,15 @@ static int pseries_rng_data_read(struct hwrng *rng, u32 *data) { - if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) { - printk(KERN_ERR "pseries rng hcall error\n"); - return 0; + int rc; + + rc = plpar_hcall(H_RANDOM, (unsigned long *)data); + if (rc != H_SUCCESS) { + pr_err_ratelimited("H_RANDOM call failed %d\n", rc); + return -EIO; } + + /* The hypervisor interface returns 64 bits */ return 8; } diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 279407a3639..5c51115081b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -93,6 +93,20 @@ config CLK_PPC_CORENET This adds the clock driver support for Freescale PowerPC corenet platforms using common clock framework. +config COMMON_CLK_XGENE + bool "Clock driver for APM XGene SoC" + default y + depends on ARM64 + ---help--- + Sypport for the APM X-Gene SoC reference, PLL, and device clocks. + +config COMMON_CLK_KEYSTONE + tristate "Clock drivers for Keystone based SOCs" + depends on ARCH_KEYSTONE && OF + ---help--- + Supports clock drivers for Keystone based SOCs. These SOCs have local + a power sleep control module that gate the clock to the IPs and PLLs. + endmenu source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7b111062ccb..7a10bc9a23e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o # SoCs specific obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o +obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o @@ -32,6 +33,8 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ +obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c new file mode 100644 index 00000000000..bac2ddf49d0 --- /dev/null +++ b/drivers/clk/clk-efm32gg.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <dt-bindings/clock/efm32-cmu.h> + +#define CMU_HFPERCLKEN0 0x44 + +static struct clk *clk[37]; +static struct clk_onecell_data clk_data = { + .clks = clk, + .clk_num = ARRAY_SIZE(clk), +}; + +static int __init efm32gg_cmu_init(struct device_node *np) +{ + int i; + void __iomem *base; + + for (i = 0; i < ARRAY_SIZE(clk); ++i) + clk[i] = ERR_PTR(-ENOENT); + + base = of_iomap(np, 0); + if (!base) { + pr_warn("Failed to map address range for efm32gg,cmu node\n"); + return -EADDRNOTAVAIL; + } + + clk[clk_HFXO] = clk_register_fixed_rate(NULL, "HFXO", NULL, + CLK_IS_ROOT, 48000000); + + clk[clk_HFPERCLKUSART0] = clk_register_gate(NULL, "HFPERCLK.USART0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 0, 0, NULL); + clk[clk_HFPERCLKUSART1] = clk_register_gate(NULL, "HFPERCLK.USART1", + "HFXO", 0, base + CMU_HFPERCLKEN0, 1, 0, NULL); + clk[clk_HFPERCLKUSART2] = clk_register_gate(NULL, "HFPERCLK.USART2", + "HFXO", 0, base + CMU_HFPERCLKEN0, 2, 0, NULL); + clk[clk_HFPERCLKUART0] = clk_register_gate(NULL, "HFPERCLK.UART0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 3, 0, NULL); + clk[clk_HFPERCLKUART1] = clk_register_gate(NULL, "HFPERCLK.UART1", + "HFXO", 0, base + CMU_HFPERCLKEN0, 4, 0, NULL); + clk[clk_HFPERCLKTIMER0] = clk_register_gate(NULL, "HFPERCLK.TIMER0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 5, 0, NULL); + clk[clk_HFPERCLKTIMER1] = clk_register_gate(NULL, "HFPERCLK.TIMER1", + "HFXO", 0, base + CMU_HFPERCLKEN0, 6, 0, NULL); + clk[clk_HFPERCLKTIMER2] = clk_register_gate(NULL, "HFPERCLK.TIMER2", + "HFXO", 0, base + CMU_HFPERCLKEN0, 7, 0, NULL); + clk[clk_HFPERCLKTIMER3] = clk_register_gate(NULL, "HFPERCLK.TIMER3", + "HFXO", 0, base + CMU_HFPERCLKEN0, 8, 0, NULL); + clk[clk_HFPERCLKACMP0] = clk_register_gate(NULL, "HFPERCLK.ACMP0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 9, 0, NULL); + clk[clk_HFPERCLKACMP1] = clk_register_gate(NULL, "HFPERCLK.ACMP1", + "HFXO", 0, base + CMU_HFPERCLKEN0, 10, 0, NULL); + clk[clk_HFPERCLKI2C0] = clk_register_gate(NULL, "HFPERCLK.I2C0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 11, 0, NULL); + clk[clk_HFPERCLKI2C1] = clk_register_gate(NULL, "HFPERCLK.I2C1", + "HFXO", 0, base + CMU_HFPERCLKEN0, 12, 0, NULL); + clk[clk_HFPERCLKGPIO] = clk_register_gate(NULL, "HFPERCLK.GPIO", + "HFXO", 0, base + CMU_HFPERCLKEN0, 13, 0, NULL); + clk[clk_HFPERCLKVCMP] = clk_register_gate(NULL, "HFPERCLK.VCMP", + "HFXO", 0, base + CMU_HFPERCLKEN0, 14, 0, NULL); + clk[clk_HFPERCLKPRS] = clk_register_gate(NULL, "HFPERCLK.PRS", + "HFXO", 0, base + CMU_HFPERCLKEN0, 15, 0, NULL); + clk[clk_HFPERCLKADC0] = clk_register_gate(NULL, "HFPERCLK.ADC0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 16, 0, NULL); + clk[clk_HFPERCLKDAC0] = clk_register_gate(NULL, "HFPERCLK.DAC0", + "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); + + return of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} +CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c index e9587073bd3..c4f76ed914b 100644 --- a/drivers/clk/clk-ppc-corenet.c +++ b/drivers/clk/clk-ppc-corenet.c @@ -11,6 +11,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of.h> #include <linux/slab.h> diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 805b4c34400..b131041c8f4 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -391,14 +391,8 @@ static int wm831x_clk_probe(struct platform_device *pdev) return 0; } -static int wm831x_clk_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver wm831x_clk_driver = { .probe = wm831x_clk_probe, - .remove = wm831x_clk_remove, .driver = { .name = "wm831x-clk", .owner = THIS_MODULE, diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c new file mode 100644 index 00000000000..dd8a62d8f11 --- /dev/null +++ b/drivers/clk/clk-xgene.c @@ -0,0 +1,521 @@ +/* + * clk-xgene.c - AppliedMicro X-Gene Clock Interface + * + * Copyright (c) 2013, Applied Micro Circuits Corporation + * Author: Loc Ho <lho@apm.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <asm/setup.h> + +/* Register SCU_PCPPLL bit fields */ +#define N_DIV_RD(src) (((src) & 0x000001ff)) + +/* Register SCU_SOCPLL bit fields */ +#define CLKR_RD(src) (((src) & 0x07000000)>>24) +#define CLKOD_RD(src) (((src) & 0x00300000)>>20) +#define REGSPEC_RESET_F1_MASK 0x00010000 +#define CLKF_RD(src) (((src) & 0x000001ff)) + +#define XGENE_CLK_DRIVER_VER "0.1" + +static DEFINE_SPINLOCK(clk_lock); + +static inline u32 xgene_clk_read(void *csr) +{ + return readl_relaxed(csr); +} + +static inline void xgene_clk_write(u32 data, void *csr) +{ + return writel_relaxed(data, csr); +} + +/* PLL Clock */ +enum xgene_pll_type { + PLL_TYPE_PCP = 0, + PLL_TYPE_SOC = 1, +}; + +struct xgene_clk_pll { + struct clk_hw hw; + const char *name; + void __iomem *reg; + spinlock_t *lock; + u32 pll_offset; + enum xgene_pll_type type; +}; + +#define to_xgene_clk_pll(_hw) container_of(_hw, struct xgene_clk_pll, hw) + +static int xgene_clk_pll_is_enabled(struct clk_hw *hw) +{ + struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw); + u32 data; + + data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); + pr_debug("%s pll %s\n", pllclk->name, + data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled"); + + return data & REGSPEC_RESET_F1_MASK ? 0 : 1; +} + +static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct xgene_clk_pll *pllclk = to_xgene_clk_pll(hw); + unsigned long fref; + unsigned long fvco; + u32 pll; + u32 nref; + u32 nout; + u32 nfb; + + pll = xgene_clk_read(pllclk->reg + pllclk->pll_offset); + + if (pllclk->type == PLL_TYPE_PCP) { + /* + * PLL VCO = Reference clock * NF + * PCP PLL = PLL_VCO / 2 + */ + nout = 2; + fvco = parent_rate * (N_DIV_RD(pll) + 4); + } else { + /* + * Fref = Reference Clock / NREF; + * Fvco = Fref * NFB; + * Fout = Fvco / NOUT; + */ + nref = CLKR_RD(pll) + 1; + nout = CLKOD_RD(pll) + 1; + nfb = CLKF_RD(pll); + fref = parent_rate / nref; + fvco = fref * nfb; + } + pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name, + fvco / nout, parent_rate); + + return fvco / nout; +} + +const struct clk_ops xgene_clk_pll_ops = { + .is_enabled = xgene_clk_pll_is_enabled, + .recalc_rate = xgene_clk_pll_recalc_rate, +}; + +static struct clk *xgene_register_clk_pll(struct device *dev, + const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg, u32 pll_offset, + u32 type, spinlock_t *lock) +{ + struct xgene_clk_pll *apmclk; + struct clk *clk; + struct clk_init_data init; + + /* allocate the APM clock structure */ + apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); + if (!apmclk) { + pr_err("%s: could not allocate APM clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &xgene_clk_pll_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + apmclk->name = name; + apmclk->reg = reg; + apmclk->lock = lock; + apmclk->pll_offset = pll_offset; + apmclk->type = type; + apmclk->hw.init = &init; + + /* Register the clock */ + clk = clk_register(dev, &apmclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, name); + kfree(apmclk); + return NULL; + } + return clk; +} + +static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_type) +{ + const char *clk_name = np->full_name; + struct clk *clk; + void *reg; + + reg = of_iomap(np, 0); + if (reg == NULL) { + pr_err("Unable to map CSR register for %s\n", np->full_name); + return; + } + of_property_read_string(np, "clock-output-names", &clk_name); + clk = xgene_register_clk_pll(NULL, + clk_name, of_clk_get_parent_name(np, 0), + CLK_IS_ROOT, reg, 0, pll_type, &clk_lock); + if (!IS_ERR(clk)) { + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, clk_name, NULL); + pr_debug("Add %s clock PLL\n", clk_name); + } +} + +static void xgene_socpllclk_init(struct device_node *np) +{ + xgene_pllclk_init(np, PLL_TYPE_SOC); +} + +static void xgene_pcppllclk_init(struct device_node *np) +{ + xgene_pllclk_init(np, PLL_TYPE_PCP); +} + +/* IP Clock */ +struct xgene_dev_parameters { + void __iomem *csr_reg; /* CSR for IP clock */ + u32 reg_clk_offset; /* Offset to clock enable CSR */ + u32 reg_clk_mask; /* Mask bit for clock enable */ + u32 reg_csr_offset; /* Offset to CSR reset */ + u32 reg_csr_mask; /* Mask bit for disable CSR reset */ + void __iomem *divider_reg; /* CSR for divider */ + u32 reg_divider_offset; /* Offset to divider register */ + u32 reg_divider_shift; /* Bit shift to divider field */ + u32 reg_divider_width; /* Width of the bit to divider field */ +}; + +struct xgene_clk { + struct clk_hw hw; + const char *name; + spinlock_t *lock; + struct xgene_dev_parameters param; +}; + +#define to_xgene_clk(_hw) container_of(_hw, struct xgene_clk, hw) + +static int xgene_clk_enable(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock enabled\n", pclk->name); + /* First enable the clock */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + data |= pclk->param.reg_clk_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_clk_offset); + pr_debug("%s clock PADDR base 0x%016LX clk offset 0x%08X mask 0x%08X value 0x%08X\n", + pclk->name, __pa(pclk->param.csr_reg), + pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, + data); + + /* Second enable the CSR */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_csr_offset); + data &= ~pclk->param.reg_csr_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_csr_offset); + pr_debug("%s CSR RESET PADDR base 0x%016LX csr offset 0x%08X mask 0x%08X value 0x%08X\n", + pclk->name, __pa(pclk->param.csr_reg), + pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, + data); + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + + return 0; +} + +static void xgene_clk_disable(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock disabled\n", pclk->name); + /* First put the CSR in reset */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_csr_offset); + data |= pclk->param.reg_csr_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_csr_offset); + + /* Second disable the clock */ + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + data &= ~pclk->param.reg_clk_mask; + xgene_clk_write(data, pclk->param.csr_reg + + pclk->param.reg_clk_offset); + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); +} + +static int xgene_clk_is_enabled(struct clk_hw *hw) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + u32 data = 0; + + if (pclk->param.csr_reg != NULL) { + pr_debug("%s clock checking\n", pclk->name); + data = xgene_clk_read(pclk->param.csr_reg + + pclk->param.reg_clk_offset); + pr_debug("%s clock is %s\n", pclk->name, + data & pclk->param.reg_clk_mask ? "enabled" : + "disabled"); + } + + if (pclk->param.csr_reg == NULL) + return 1; + return data & pclk->param.reg_clk_mask ? 1 : 0; +} + +static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + u32 data; + + if (pclk->param.divider_reg) { + data = xgene_clk_read(pclk->param.divider_reg + + pclk->param.reg_divider_offset); + data >>= pclk->param.reg_divider_shift; + data &= (1 << pclk->param.reg_divider_width) - 1; + + pr_debug("%s clock recalc rate %ld parent %ld\n", + pclk->name, parent_rate / data, parent_rate); + return parent_rate / data; + } else { + pr_debug("%s clock recalc rate %ld parent %ld\n", + pclk->name, parent_rate, parent_rate); + return parent_rate; + } +} + +static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long flags = 0; + u32 data; + u32 divider; + u32 divider_save; + + if (pclk->lock) + spin_lock_irqsave(pclk->lock, flags); + + if (pclk->param.divider_reg) { + /* Let's compute the divider */ + if (rate > parent_rate) + rate = parent_rate; + divider_save = divider = parent_rate / rate; /* Rounded down */ + divider &= (1 << pclk->param.reg_divider_width) - 1; + divider <<= pclk->param.reg_divider_shift; + + /* Set new divider */ + data = xgene_clk_read(pclk->param.divider_reg + + pclk->param.reg_divider_offset); + data &= ~((1 << pclk->param.reg_divider_width) - 1); + data |= divider; + xgene_clk_write(data, pclk->param.divider_reg + + pclk->param.reg_divider_offset); + pr_debug("%s clock set rate %ld\n", pclk->name, + parent_rate / divider_save); + } else { + divider_save = 1; + } + + if (pclk->lock) + spin_unlock_irqrestore(pclk->lock, flags); + + return parent_rate / divider_save; +} + +static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct xgene_clk *pclk = to_xgene_clk(hw); + unsigned long parent_rate = *prate; + u32 divider; + + if (pclk->param.divider_reg) { + /* Let's compute the divider */ + if (rate > parent_rate) + rate = parent_rate; + divider = parent_rate / rate; /* Rounded down */ + } else { + divider = 1; + } + + return parent_rate / divider; +} + +const struct clk_ops xgene_clk_ops = { + .enable = xgene_clk_enable, + .disable = xgene_clk_disable, + .is_enabled = xgene_clk_is_enabled, + .recalc_rate = xgene_clk_recalc_rate, + .set_rate = xgene_clk_set_rate, + .round_rate = xgene_clk_round_rate, +}; + +static struct clk *xgene_register_clk(struct device *dev, + const char *name, const char *parent_name, + struct xgene_dev_parameters *parameters, spinlock_t *lock) +{ + struct xgene_clk *apmclk; + struct clk *clk; + struct clk_init_data init; + int rc; + + /* allocate the APM clock structure */ + apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); + if (!apmclk) { + pr_err("%s: could not allocate APM clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &xgene_clk_ops; + init.flags = 0; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + apmclk->name = name; + apmclk->lock = lock; + apmclk->hw.init = &init; + apmclk->param = *parameters; + + /* Register the clock */ + clk = clk_register(dev, &apmclk->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, name); + kfree(apmclk); + return clk; + } + + /* Register the clock for lookup */ + rc = clk_register_clkdev(clk, name, NULL); + if (rc != 0) { + pr_err("%s: could not register lookup clk %s\n", + __func__, name); + } + return clk; +} + +static void __init xgene_devclk_init(struct device_node *np) +{ + const char *clk_name = np->full_name; + struct clk *clk; + struct resource res; + int rc; + struct xgene_dev_parameters parameters; + int i; + + /* Check if the entry is disabled */ + if (!of_device_is_available(np)) + return; + + /* Parse the DTS register for resource */ + parameters.csr_reg = NULL; + parameters.divider_reg = NULL; + for (i = 0; i < 2; i++) { + void *map_res; + rc = of_address_to_resource(np, i, &res); + if (rc != 0) { + if (i == 0) { + pr_err("no DTS register for %s\n", + np->full_name); + return; + } + break; + } + map_res = of_iomap(np, i); + if (map_res == NULL) { + pr_err("Unable to map resource %d for %s\n", + i, np->full_name); + goto err; + } + if (strcmp(res.name, "div-reg") == 0) + parameters.divider_reg = map_res; + else /* if (strcmp(res->name, "csr-reg") == 0) */ + parameters.csr_reg = map_res; + } + if (of_property_read_u32(np, "csr-offset", ¶meters.reg_csr_offset)) + parameters.reg_csr_offset = 0; + if (of_property_read_u32(np, "csr-mask", ¶meters.reg_csr_mask)) + parameters.reg_csr_mask = 0xF; + if (of_property_read_u32(np, "enable-offset", + ¶meters.reg_clk_offset)) + parameters.reg_clk_offset = 0x8; + if (of_property_read_u32(np, "enable-mask", ¶meters.reg_clk_mask)) + parameters.reg_clk_mask = 0xF; + if (of_property_read_u32(np, "divider-offset", + ¶meters.reg_divider_offset)) + parameters.reg_divider_offset = 0; + if (of_property_read_u32(np, "divider-width", + ¶meters.reg_divider_width)) + parameters.reg_divider_width = 0; + if (of_property_read_u32(np, "divider-shift", + ¶meters.reg_divider_shift)) + parameters.reg_divider_shift = 0; + of_property_read_string(np, "clock-output-names", &clk_name); + + clk = xgene_register_clk(NULL, clk_name, + of_clk_get_parent_name(np, 0), ¶meters, &clk_lock); + if (IS_ERR(clk)) + goto err; + pr_debug("Add %s clock\n", clk_name); + rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); + if (rc != 0) + pr_err("%s: could register provider clk %s\n", __func__, + np->full_name); + + return; + +err: + if (parameters.csr_reg) + iounmap(parameters.csr_reg); + if (parameters.divider_reg) + iounmap(parameters.divider_reg); +} + +CLK_OF_DECLARE(xgene_socpll_clock, "apm,xgene-socpll-clock", xgene_socpllclk_init); +CLK_OF_DECLARE(xgene_pcppll_clock, "apm,xgene-pcppll-clock", xgene_pcppllclk_init); +CLK_OF_DECLARE(xgene_dev_clock, "apm,xgene-device-clock", xgene_devclk_init); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a004769528e..2cf2ea6b77a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1080,13 +1080,16 @@ unsigned long clk_get_rate(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_get_rate); -static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent) +static int clk_fetch_parent_index(struct clk *clk, struct clk *parent) { - u8 i; + int i; - if (!clk->parents) - clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents), - GFP_KERNEL); + if (!clk->parents) { + clk->parents = kcalloc(clk->num_parents, + sizeof(struct clk *), GFP_KERNEL); + if (!clk->parents) + return -ENOMEM; + } /* * find index of new parent clock using cached parent ptrs, @@ -1094,16 +1097,19 @@ static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent) * them now to avoid future calls to __clk_lookup. */ for (i = 0; i < clk->num_parents; i++) { - if (clk->parents && clk->parents[i] == parent) - break; - else if (!strcmp(clk->parent_names[i], parent->name)) { - if (clk->parents) - clk->parents[i] = __clk_lookup(parent->name); - break; + if (clk->parents[i] == parent) + return i; + + if (clk->parents[i]) + continue; + + if (!strcmp(clk->parent_names[i], parent->name)) { + clk->parents[i] = __clk_lookup(parent->name); + return i; } } - return i; + return -EINVAL; } static void clk_reparent(struct clk *clk, struct clk *new_parent) @@ -1265,7 +1271,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) struct clk *old_parent, *parent; unsigned long best_parent_rate = 0; unsigned long new_rate; - u8 p_index = 0; + int p_index = 0; /* sanity */ if (IS_ERR_OR_NULL(clk)) @@ -1306,7 +1312,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) /* try finding the new parent index */ if (parent) { p_index = clk_fetch_parent_index(clk, parent); - if (p_index == clk->num_parents) { + if (p_index < 0) { pr_debug("%s: clk %s can not be parent of clk %s\n", __func__, parent->name, clk->name); return NULL; @@ -1532,7 +1538,7 @@ static struct clk *__clk_init_parent(struct clk *clk) if (!clk->parents) clk->parents = - kzalloc((sizeof(struct clk*) * clk->num_parents), + kcalloc(clk->num_parents, sizeof(struct clk *), GFP_KERNEL); ret = clk_get_parent_by_index(clk, index); @@ -1568,7 +1574,7 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent) int clk_set_parent(struct clk *clk, struct clk *parent) { int ret = 0; - u8 p_index = 0; + int p_index = 0; unsigned long p_rate = 0; if (!clk) @@ -1597,10 +1603,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent) if (parent) { p_index = clk_fetch_parent_index(clk, parent); p_rate = parent->rate; - if (p_index == clk->num_parents) { + if (p_index < 0) { pr_debug("%s: clk %s can not be parent of clk %s\n", __func__, parent->name, clk->name); - ret = -EINVAL; + ret = p_index; goto out; } } @@ -1689,8 +1695,8 @@ int __clk_init(struct device *dev, struct clk *clk) * for clock drivers to statically initialize clk->parents. */ if (clk->num_parents > 1 && !clk->parents) { - clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents), - GFP_KERNEL); + clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *), + GFP_KERNEL); /* * __clk_lookup returns NULL for parents that have not been * clk_init'd; thus any access to clk->parents[] must check @@ -1830,8 +1836,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) hw->clk = clk; /* allocate local copy in case parent_names is __initdata */ - clk->parent_names = kzalloc((sizeof(char*) * clk->num_parents), - GFP_KERNEL); + clk->parent_names = kcalloc(clk->num_parents, sizeof(char *), + GFP_KERNEL); if (!clk->parent_names) { pr_err("%s: could not allocate clk->parent_names\n", __func__); @@ -2196,6 +2202,12 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) return clk; } +int of_clk_get_parent_count(struct device_node *np) +{ + return of_count_phandle_with_args(np, "clocks", "#clock-cells"); +} +EXPORT_SYMBOL_GPL(of_clk_get_parent_count); + const char *of_clk_get_parent_name(struct device_node *np, int index) { struct of_phandle_args clkspec; diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile new file mode 100644 index 00000000000..0477cf63f13 --- /dev/null +++ b/drivers/clk/keystone/Makefile @@ -0,0 +1 @@ +obj-y += pll.o gate.o diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c new file mode 100644 index 00000000000..1f333bcfc22 --- /dev/null +++ b/drivers/clk/keystone/gate.c @@ -0,0 +1,264 @@ +/* + * Clock driver for Keystone 2 based devices + * + * Copyright (C) 2013 Texas Instruments. + * Murali Karicheri <m-karicheri2@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/of_address.h> +#include <linux/of.h> +#include <linux/module.h> + +/* PSC register offsets */ +#define PTCMD 0x120 +#define PTSTAT 0x128 +#define PDSTAT 0x200 +#define PDCTL 0x300 +#define MDSTAT 0x800 +#define MDCTL 0xa00 + +/* PSC module states */ +#define PSC_STATE_SWRSTDISABLE 0 +#define PSC_STATE_SYNCRST 1 +#define PSC_STATE_DISABLE 2 +#define PSC_STATE_ENABLE 3 + +#define MDSTAT_STATE_MASK 0x3f +#define MDSTAT_MCKOUT BIT(12) +#define PDSTAT_STATE_MASK 0x1f +#define MDCTL_FORCE BIT(31) +#define MDCTL_LRESET BIT(8) +#define PDCTL_NEXT BIT(0) + +/* Maximum timeout to bail out state transition for module */ +#define STATE_TRANS_MAX_COUNT 0xffff + +static void __iomem *domain_transition_base; + +/** + * struct clk_psc_data - PSC data + * @control_base: Base address for a PSC control + * @domain_base: Base address for a PSC domain + * @domain_id: PSC domain id number + */ +struct clk_psc_data { + void __iomem *control_base; + void __iomem *domain_base; + u32 domain_id; +}; + +/** + * struct clk_psc - PSC clock structure + * @hw: clk_hw for the psc + * @psc_data: PSC driver specific data + * @lock: Spinlock used by the driver + */ +struct clk_psc { + struct clk_hw hw; + struct clk_psc_data *psc_data; + spinlock_t *lock; +}; + +static DEFINE_SPINLOCK(psc_lock); + +#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw) + +static void psc_config(void __iomem *control_base, void __iomem *domain_base, + u32 next_state, u32 domain_id) +{ + u32 ptcmd, pdstat, pdctl, mdstat, mdctl, ptstat; + u32 count = STATE_TRANS_MAX_COUNT; + + mdctl = readl(control_base + MDCTL); + mdctl &= ~MDSTAT_STATE_MASK; + mdctl |= next_state; + /* For disable, we always put the module in local reset */ + if (next_state == PSC_STATE_DISABLE) + mdctl &= ~MDCTL_LRESET; + writel(mdctl, control_base + MDCTL); + + pdstat = readl(domain_base + PDSTAT); + if (!(pdstat & PDSTAT_STATE_MASK)) { + pdctl = readl(domain_base + PDCTL); + pdctl |= PDCTL_NEXT; + writel(pdctl, domain_base + PDCTL); + } + + ptcmd = 1 << domain_id; + writel(ptcmd, domain_transition_base + PTCMD); + do { + ptstat = readl(domain_transition_base + PTSTAT); + } while (((ptstat >> domain_id) & 1) && count--); + + count = STATE_TRANS_MAX_COUNT; + do { + mdstat = readl(control_base + MDSTAT); + } while (!((mdstat & MDSTAT_STATE_MASK) == next_state) && count--); +} + +static int keystone_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_psc *psc = to_clk_psc(hw); + struct clk_psc_data *data = psc->psc_data; + u32 mdstat = readl(data->control_base + MDSTAT); + + return (mdstat & MDSTAT_MCKOUT) ? 1 : 0; +} + +static int keystone_clk_enable(struct clk_hw *hw) +{ + struct clk_psc *psc = to_clk_psc(hw); + struct clk_psc_data *data = psc->psc_data; + unsigned long flags = 0; + + if (psc->lock) + spin_lock_irqsave(psc->lock, flags); + + psc_config(data->control_base, data->domain_base, + PSC_STATE_ENABLE, data->domain_id); + + if (psc->lock) + spin_unlock_irqrestore(psc->lock, flags); + + return 0; +} + +static void keystone_clk_disable(struct clk_hw *hw) +{ + struct clk_psc *psc = to_clk_psc(hw); + struct clk_psc_data *data = psc->psc_data; + unsigned long flags = 0; + + if (psc->lock) + spin_lock_irqsave(psc->lock, flags); + + psc_config(data->control_base, data->domain_base, + PSC_STATE_DISABLE, data->domain_id); + + if (psc->lock) + spin_unlock_irqrestore(psc->lock, flags); +} + +static const struct clk_ops clk_psc_ops = { + .enable = keystone_clk_enable, + .disable = keystone_clk_disable, + .is_enabled = keystone_clk_is_enabled, +}; + +/** + * clk_register_psc - register psc clock + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of clock's parent + * @psc_data: platform data to configure this clock + * @lock: spinlock used by this clock + */ +static struct clk *clk_register_psc(struct device *dev, + const char *name, + const char *parent_name, + struct clk_psc_data *psc_data, + spinlock_t *lock) +{ + struct clk_init_data init; + struct clk_psc *psc; + struct clk *clk; + + psc = kzalloc(sizeof(*psc), GFP_KERNEL); + if (!psc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_psc_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + psc->psc_data = psc_data; + psc->lock = lock; + psc->hw.init = &init; + + clk = clk_register(NULL, &psc->hw); + if (IS_ERR(clk)) + kfree(psc); + + return clk; +} + +/** + * of_psc_clk_init - initialize psc clock through DT + * @node: device tree node for this clock + * @lock: spinlock used by this clock + */ +static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock) +{ + const char *clk_name = node->name; + const char *parent_name; + struct clk_psc_data *data; + struct clk *clk; + int i; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + pr_err("%s: Out of memory\n", __func__); + return; + } + + i = of_property_match_string(node, "reg-names", "control"); + data->control_base = of_iomap(node, i); + if (!data->control_base) { + pr_err("%s: control ioremap failed\n", __func__); + goto out; + } + + i = of_property_match_string(node, "reg-names", "domain"); + data->domain_base = of_iomap(node, i); + if (!data->domain_base) { + pr_err("%s: domain ioremap failed\n", __func__); + iounmap(data->control_base); + goto out; + } + + of_property_read_u32(node, "domain-id", &data->domain_id); + + /* Domain transition registers at fixed address space of domain_id 0 */ + if (!domain_transition_base && !data->domain_id) + domain_transition_base = data->domain_base; + + of_property_read_string(node, "clock-output-names", &clk_name); + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s: Parent clock not found\n", __func__); + goto out; + } + + clk = clk_register_psc(NULL, clk_name, parent_name, data, lock); + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } + + pr_err("%s: error registering clk %s\n", __func__, node->name); +out: + kfree(data); + return; +} + +/** + * of_keystone_psc_clk_init - initialize psc clock through DT + * @node: device tree node for this clock + */ +static void __init of_keystone_psc_clk_init(struct device_node *node) +{ + of_psc_clk_init(node, &psc_lock); +} +CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock", + of_keystone_psc_clk_init); diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c new file mode 100644 index 00000000000..47a1bd9f172 --- /dev/null +++ b/drivers/clk/keystone/pll.c @@ -0,0 +1,305 @@ +/* + * PLL clock driver for Keystone devices + * + * Copyright (C) 2013 Texas Instruments Inc. + * Murali Karicheri <m-karicheri2@ti.com> + * Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/of_address.h> +#include <linux/of.h> +#include <linux/module.h> + +#define PLLM_LOW_MASK 0x3f +#define PLLM_HIGH_MASK 0x7ffc0 +#define MAIN_PLLM_HIGH_MASK 0x7f000 +#define PLLM_HIGH_SHIFT 6 +#define PLLD_MASK 0x3f + +/** + * struct clk_pll_data - pll data structure + * @has_pllctrl: If set to non zero, lower 6 bits of multiplier is in pllm + * register of pll controller, else it is in the pll_ctrl0((bit 11-6) + * @phy_pllm: Physical address of PLLM in pll controller. Used when + * has_pllctrl is non zero. + * @phy_pll_ctl0: Physical address of PLL ctrl0. This could be that of + * Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL + * or PA PLL available on keystone2. These PLLs are controlled by + * this register. Main PLL is controlled by a PLL controller. + * @pllm: PLL register map address + * @pll_ctl0: PLL controller map address + * @pllm_lower_mask: multiplier lower mask + * @pllm_upper_mask: multiplier upper mask + * @pllm_upper_shift: multiplier upper shift + * @plld_mask: divider mask + * @postdiv: Post divider + */ +struct clk_pll_data { + bool has_pllctrl; + u32 phy_pllm; + u32 phy_pll_ctl0; + void __iomem *pllm; + void __iomem *pll_ctl0; + u32 pllm_lower_mask; + u32 pllm_upper_mask; + u32 pllm_upper_shift; + u32 plld_mask; + u32 postdiv; +}; + +/** + * struct clk_pll - Main pll clock + * @hw: clk_hw for the pll + * @pll_data: PLL driver specific data + */ +struct clk_pll { + struct clk_hw hw; + struct clk_pll_data *pll_data; +}; + +#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw) + +static unsigned long clk_pllclk_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct clk_pll_data *pll_data = pll->pll_data; + unsigned long rate = parent_rate; + u32 mult = 0, prediv, postdiv, val; + + /* + * get bits 0-5 of multiplier from pllctrl PLLM register + * if has_pllctrl is non zero + */ + if (pll_data->has_pllctrl) { + val = readl(pll_data->pllm); + mult = (val & pll_data->pllm_lower_mask); + } + + /* bit6-12 of PLLM is in Main PLL control register */ + val = readl(pll_data->pll_ctl0); + mult |= ((val & pll_data->pllm_upper_mask) + >> pll_data->pllm_upper_shift); + prediv = (val & pll_data->plld_mask); + postdiv = pll_data->postdiv; + + rate /= (prediv + 1); + rate = (rate * (mult + 1)); + rate /= postdiv; + + return rate; +} + +static const struct clk_ops clk_pll_ops = { + .recalc_rate = clk_pllclk_recalc, +}; + +static struct clk *clk_register_pll(struct device *dev, + const char *name, + const char *parent_name, + struct clk_pll_data *pll_data) +{ + struct clk_init_data init; + struct clk_pll *pll; + struct clk *clk; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_pll_ops; + init.flags = 0; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + pll->pll_data = pll_data; + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + goto out; + + return clk; +out: + kfree(pll); + return NULL; +} + +/** + * _of_clk_init - PLL initialisation via DT + * @node: device tree node for this clock + * @pllctrl: If true, lower 6 bits of multiplier is in pllm register of + * pll controller, else it is in the control regsiter0(bit 11-6) + */ +static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) +{ + struct clk_pll_data *pll_data; + const char *parent_name; + struct clk *clk; + int i; + + pll_data = kzalloc(sizeof(*pll_data), GFP_KERNEL); + if (!pll_data) { + pr_err("%s: Out of memory\n", __func__); + return; + } + + parent_name = of_clk_get_parent_name(node, 0); + if (of_property_read_u32(node, "fixed-postdiv", &pll_data->postdiv)) + goto out; + + i = of_property_match_string(node, "reg-names", "control"); + pll_data->pll_ctl0 = of_iomap(node, i); + if (!pll_data->pll_ctl0) { + pr_err("%s: ioremap failed\n", __func__); + goto out; + } + + pll_data->pllm_lower_mask = PLLM_LOW_MASK; + pll_data->pllm_upper_shift = PLLM_HIGH_SHIFT; + pll_data->plld_mask = PLLD_MASK; + pll_data->has_pllctrl = pllctrl; + if (!pll_data->has_pllctrl) { + pll_data->pllm_upper_mask = PLLM_HIGH_MASK; + } else { + pll_data->pllm_upper_mask = MAIN_PLLM_HIGH_MASK; + i = of_property_match_string(node, "reg-names", "multiplier"); + pll_data->pllm = of_iomap(node, i); + if (!pll_data->pllm) { + iounmap(pll_data->pll_ctl0); + goto out; + } + } + + clk = clk_register_pll(NULL, node->name, parent_name, pll_data); + if (clk) { + of_clk_add_provider(node, of_clk_src_simple_get, clk); + return; + } + +out: + pr_err("%s: error initializing pll %s\n", __func__, node->name); + kfree(pll_data); +} + +/** + * of_keystone_pll_clk_init - PLL initialisation DT wrapper + * @node: device tree node for this clock + */ +static void __init of_keystone_pll_clk_init(struct device_node *node) +{ + _of_pll_clk_init(node, false); +} +CLK_OF_DECLARE(keystone_pll_clock, "ti,keystone,pll-clock", + of_keystone_pll_clk_init); + +/** + * of_keystone_pll_main_clk_init - Main PLL initialisation DT wrapper + * @node: device tree node for this clock + */ +static void __init of_keystone_main_pll_clk_init(struct device_node *node) +{ + _of_pll_clk_init(node, true); +} +CLK_OF_DECLARE(keystone_main_pll_clock, "ti,keystone,main-pll-clock", + of_keystone_main_pll_clk_init); + +/** + * of_pll_div_clk_init - PLL divider setup function + * @node: device tree node for this clock + */ +static void __init of_pll_div_clk_init(struct device_node *node) +{ + const char *parent_name; + void __iomem *reg; + u32 shift, mask; + struct clk *clk; + const char *clk_name = node->name; + + of_property_read_string(node, "clock-output-names", &clk_name); + reg = of_iomap(node, 0); + if (!reg) { + pr_err("%s: ioremap failed\n", __func__); + return; + } + + parent_name = of_clk_get_parent_name(node, 0); + if (!parent_name) { + pr_err("%s: missing parent clock\n", __func__); + return; + } + + if (of_property_read_u32(node, "bit-shift", &shift)) { + pr_err("%s: missing 'shift' property\n", __func__); + return; + } + + if (of_property_read_u32(node, "bit-mask", &mask)) { + pr_err("%s: missing 'bit-mask' property\n", __func__); + return; + } + + clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift, + mask, 0, NULL); + if (clk) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + else + pr_err("%s: error registering divider %s\n", __func__, clk_name); +} +CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init); + +/** + * of_pll_mux_clk_init - PLL mux setup function + * @node: device tree node for this clock + */ +static void __init of_pll_mux_clk_init(struct device_node *node) +{ + void __iomem *reg; + u32 shift, mask; + struct clk *clk; + const char *parents[2]; + const char *clk_name = node->name; + + of_property_read_string(node, "clock-output-names", &clk_name); + reg = of_iomap(node, 0); + if (!reg) { + pr_err("%s: ioremap failed\n", __func__); + return; + } + + parents[0] = of_clk_get_parent_name(node, 0); + parents[1] = of_clk_get_parent_name(node, 1); + if (!parents[0] || !parents[1]) { + pr_err("%s: missing parent clocks\n", __func__); + return; + } + + if (of_property_read_u32(node, "bit-shift", &shift)) { + pr_err("%s: missing 'shift' property\n", __func__); + return; + } + + if (of_property_read_u32(node, "bit-mask", &mask)) { + pr_err("%s: missing 'bit-mask' property\n", __func__); + return; + } + + clk = clk_register_mux(NULL, clk_name, (const char **)&parents, + ARRAY_SIZE(parents) , 0, reg, shift, mask, + 0, NULL); + if (clk) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + else + pr_err("%s: error registering mux %s\n", __func__, clk_name); +} +CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init); diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index cc40fe64f2d..10772aa72e4 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -117,13 +117,19 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk, goto err; fclk_gate_lock = kmalloc(sizeof(*fclk_gate_lock), GFP_KERNEL); if (!fclk_gate_lock) - goto err; + goto err_fclk_gate_lock; spin_lock_init(fclk_lock); spin_lock_init(fclk_gate_lock); mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name); + if (!mux_name) + goto err_mux_name; div0_name = kasprintf(GFP_KERNEL, "%s_div0", clk_name); + if (!div0_name) + goto err_div0_name; div1_name = kasprintf(GFP_KERNEL, "%s_div1", clk_name); + if (!div1_name) + goto err_div1_name; clk = clk_register_mux(NULL, mux_name, parents, 4, CLK_SET_RATE_NO_REPARENT, fclk_ctrl_reg, 4, 2, 0, @@ -147,6 +153,14 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk, return; +err_div1_name: + kfree(div0_name); +err_div0_name: + kfree(mux_name); +err_mux_name: + kfree(fclk_gate_lock); +err_fclk_gate_lock: + kfree(fclk_lock); err: clks[fclk] = ERR_PTR(-ENOMEM); } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 971d796e071..bdb953e15d2 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -34,6 +34,7 @@ config ORION_TIMER bool config SUN4I_TIMER + select CLKSRC_MMIO bool config VT8500_TIMER @@ -71,10 +72,33 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK help Use the always on PRCMU Timer as sched_clock +config CLKSRC_EFM32 + bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32 + depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) + default ARCH_EFM32 + help + Support to use the timers of EFM32 SoCs as clock source and clock + event device. + config ARM_ARCH_TIMER bool select CLKSRC_OF if OF +config ARM_ARCH_TIMER_EVTSTREAM + bool "Support for ARM architected timer event stream generation" + default y if ARM_ARCH_TIMER + help + This option enables support for event stream generation based on + the ARM architected timer. It is used for waking up CPUs executing + the wfe instruction at a frequency represented as a power-of-2 + divisor of the clock rate. + The main use of the event stream is wfe-based timeouts of userspace + locking implementations. It might also be useful for imposing timeout + on wfe to safeguard against any programming errors in case an expected + event is not generated. + This must be disabled for hardware validation purposes to detect any + hardware anomalies of missing events. + config ARM_GLOBAL_TIMER bool select CLKSRC_OF if OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 704d6d342ad..33621efb914 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o obj-$(CONFIG_ARCH_BCM) += bcm_kona_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o +obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd5e11..95fb944e15e 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -13,12 +13,14 @@ #include <linux/device.h> #include <linux/smp.h> #include <linux/cpu.h> +#include <linux/cpu_pm.h> #include <linux/clockchips.h> #include <linux/interrupt.h> #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/sched_clock.h> #include <asm/arch_timer.h> #include <asm/virt.h> @@ -294,6 +296,19 @@ static void __arch_timer_setup(unsigned type, clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); } +static void arch_timer_configure_evtstream(void) +{ + int evt_stream_div, pos; + + /* Find the closest power of two to the divisor */ + evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ; + pos = fls(evt_stream_div); + if (pos > 1 && !(evt_stream_div & (1 << (pos - 2)))) + pos--; + /* enable event stream */ + arch_timer_evtstrm_enable(min(pos, 15)); +} + static int arch_timer_setup(struct clock_event_device *clk) { __arch_timer_setup(ARCH_CP15_TIMER, clk); @@ -307,6 +322,8 @@ static int arch_timer_setup(struct clock_event_device *clk) } arch_counter_set_user_access(); + if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) + arch_timer_configure_evtstream(); return 0; } @@ -389,7 +406,7 @@ static struct clocksource clocksource_counter = { .rating = 400, .read = arch_counter_read, .mask = CLOCKSOURCE_MASK(56), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, + .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP, }; static struct cyclecounter cyclecounter = { @@ -419,6 +436,9 @@ static void __init arch_counter_register(unsigned type) cyclecounter.mult = clocksource_counter.mult; cyclecounter.shift = clocksource_counter.shift; timecounter_init(&timecounter, &cyclecounter, start_count); + + /* 56 bits minimum, so we assume worst case rollover */ + sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate); } static void arch_timer_stop(struct clock_event_device *clk) @@ -460,6 +480,33 @@ static struct notifier_block arch_timer_cpu_nb = { .notifier_call = arch_timer_cpu_notify, }; +#ifdef CONFIG_CPU_PM +static unsigned int saved_cntkctl; +static int arch_timer_cpu_pm_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + if (action == CPU_PM_ENTER) + saved_cntkctl = arch_timer_get_cntkctl(); + else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) + arch_timer_set_cntkctl(saved_cntkctl); + return NOTIFY_OK; +} + +static struct notifier_block arch_timer_cpu_pm_notifier = { + .notifier_call = arch_timer_cpu_pm_notify, +}; + +static int __init arch_timer_cpu_pm_init(void) +{ + return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier); +} +#else +static int __init arch_timer_cpu_pm_init(void) +{ + return 0; +} +#endif + static int __init arch_timer_register(void) { int err; @@ -499,11 +546,17 @@ static int __init arch_timer_register(void) if (err) goto out_free_irq; + err = arch_timer_cpu_pm_init(); + if (err) + goto out_unreg_notify; + /* Immediately configure the timer on the boot CPU */ arch_timer_setup(this_cpu_ptr(arch_timer_evt)); return 0; +out_unreg_notify: + unregister_cpu_notifier(&arch_timer_cpu_nb); out_free_irq: if (arch_timer_use_virtual) free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index b66c1f36066..c639b1a9e99 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -169,7 +169,8 @@ static int gt_clockevents_init(struct clock_event_device *clk) int cpu = smp_processor_id(); clk->name = "arm_global_timer"; - clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERCPU; clk->set_mode = gt_clockevent_set_mode; clk->set_next_event = gt_clockevent_set_next_event; clk->cpumask = cpumask_of(cpu); diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 07ea7ce900d..26ed331b1aa 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -49,7 +49,7 @@ struct bcm2835_timer { static void __iomem *system_clock __read_mostly; -static u32 notrace bcm2835_sched_read(void) +static u64 notrace bcm2835_sched_read(void) { return readl_relaxed(system_clock); } @@ -110,7 +110,7 @@ static void __init bcm2835_timer_init(struct device_node *node) panic("Can't read clock-frequency"); system_clock = base + REG_COUNTER_LO; - setup_sched_clock(bcm2835_sched_read, 32, freq); + sched_clock_register(bcm2835_sched_read, 32, freq); clocksource_mmio_init(base + REG_COUNTER_LO, node->name, freq, 300, 32, clocksource_mmio_readl_up); diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index a9fd4ad2567..b375106844d 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -53,7 +53,7 @@ static struct clocksource clocksource_dbx500_prcmu = { #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK -static u32 notrace dbx500_prcmu_sched_clock_read(void) +static u64 notrace dbx500_prcmu_sched_clock_read(void) { if (unlikely(!clksrc_dbx500_timer_base)) return 0; @@ -81,8 +81,7 @@ void __init clksrc_dbx500_prcmu_init(void __iomem *base) clksrc_dbx500_timer_base + PRCMU_TIMER_REF); } #ifdef CONFIG_CLKSRC_DBX500_PRCMU_SCHED_CLOCK - setup_sched_clock(dbx500_prcmu_sched_clock_read, - 32, RATE_32K); + sched_clock_register(dbx500_prcmu_sched_clock_read, 32, RATE_32K); #endif clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index b9ddd9e3a2f..35639cf4e5a 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c @@ -35,5 +35,6 @@ void __init clocksource_of_init(void) init_func = match->data; init_func(np); + of_node_put(np); } } diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index 4cbae4f762b..45ba8aecc72 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c @@ -23,7 +23,7 @@ #include <linux/clk.h> #include <linux/sched_clock.h> -static void timer_get_base_and_rate(struct device_node *np, +static void __init timer_get_base_and_rate(struct device_node *np, void __iomem **base, u32 *rate) { struct clk *timer_clk; @@ -55,11 +55,11 @@ static void timer_get_base_and_rate(struct device_node *np, try_clock_freq: if (of_property_read_u32(np, "clock-freq", rate) && - of_property_read_u32(np, "clock-frequency", rate)) + of_property_read_u32(np, "clock-frequency", rate)) panic("No clock nor clock-frequency property for %s", np->name); } -static void add_clockevent(struct device_node *event_timer) +static void __init add_clockevent(struct device_node *event_timer) { void __iomem *iobase; struct dw_apb_clock_event_device *ced; @@ -82,7 +82,7 @@ static void add_clockevent(struct device_node *event_timer) static void __iomem *sched_io_base; static u32 sched_rate; -static void add_clocksource(struct device_node *source_timer) +static void __init add_clocksource(struct device_node *source_timer) { void __iomem *iobase; struct dw_apb_clocksource *cs; @@ -106,7 +106,7 @@ static void add_clocksource(struct device_node *source_timer) sched_rate = rate; } -static u32 read_sched_clock(void) +static u64 read_sched_clock(void) { return __raw_readl(sched_io_base); } @@ -117,7 +117,7 @@ static const struct of_device_id sptimer_ids[] __initconst = { { /* Sentinel */ }, }; -static void init_sched_clock(void) +static void __init init_sched_clock(void) { struct device_node *sched_timer; @@ -128,7 +128,7 @@ static void init_sched_clock(void) of_node_put(sched_timer); } - setup_sched_clock(read_sched_clock, 32, sched_rate); + sched_clock_register(read_sched_clock, 32, sched_rate); } static int num_called; @@ -138,12 +138,10 @@ static void __init dw_apb_timer_init(struct device_node *timer) case 0: pr_debug("%s: found clockevent timer\n", __func__); add_clockevent(timer); - of_node_put(timer); break; case 1: pr_debug("%s: found clocksource timer\n", __func__); add_clocksource(timer); - of_node_put(timer); init_sched_clock(); break; default: diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 3a5909c12d4..9d170834fcf 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -78,7 +78,7 @@ static int em_sti_enable(struct em_sti_priv *p) int ret; /* enable clock */ - ret = clk_enable(p->clk); + ret = clk_prepare_enable(p->clk); if (ret) { dev_err(&p->pdev->dev, "cannot enable clock\n"); return ret; @@ -107,7 +107,7 @@ static void em_sti_disable(struct em_sti_priv *p) em_sti_write(p, STI_INTENCLR, 3); /* stop clock */ - clk_disable(p->clk); + clk_disable_unprepare(p->clk); } static cycle_t em_sti_count(struct em_sti_priv *p) diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 0f5e65f74dc..445b68a01dc 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -222,7 +222,7 @@ static struct clocksource clocksource_mxs = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static u32 notrace mxs_read_sched_clock_v2(void) +static u64 notrace mxs_read_sched_clock_v2(void) { return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1)); } @@ -236,7 +236,7 @@ static int __init mxs_clocksource_init(struct clk *timer_clk) else { clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1), "mxs_timer", c, 200, 32, clocksource_mmio_readl_down); - setup_sched_clock(mxs_read_sched_clock_v2, 32, c); + sched_clock_register(mxs_read_sched_clock_v2, 32, c); } return 0; diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 1b74bea1238..ed7b73b508e 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -76,7 +76,7 @@ static struct delay_timer mtu_delay_timer; * local implementation which uses the clocksource to get some * better resolution when scheduling the kernel. */ -static u32 notrace nomadik_read_sched_clock(void) +static u64 notrace nomadik_read_sched_clock(void) { if (unlikely(!mtu_base)) return 0; @@ -231,7 +231,7 @@ static void __init __nmdk_timer_init(void __iomem *base, int irq, "mtu_0"); #ifdef CONFIG_CLKSRC_NOMADIK_MTU_SCHED_CLOCK - setup_sched_clock(nomadik_read_sched_clock, 32, rate); + sched_clock_register(nomadik_read_sched_clock, 32, rate); #endif /* Timer 1 is used for events, register irq and clockevents */ diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index ab29476ee5f..85082e8d305 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -331,7 +331,7 @@ static struct clocksource samsung_clocksource = { * this wraps around for now, since it is just a relative time * stamp. (Inspired by U300 implementation.) */ -static u32 notrace samsung_read_sched_clock(void) +static u64 notrace samsung_read_sched_clock(void) { return samsung_clocksource_read(NULL); } @@ -357,7 +357,7 @@ static void __init samsung_clocksource_init(void) else pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14; - setup_sched_clock(samsung_read_sched_clock, + sched_clock_register(samsung_read_sched_clock, pwm.variant.bits, clock_rate); samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits); diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 8ead0258740..2fb4695a28d 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -37,6 +37,8 @@ #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14) #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18) +#define TIMER_SYNC_TICKS 3 + static void __iomem *timer_base; static u32 ticks_per_jiffy; @@ -50,7 +52,7 @@ static void sun4i_clkevt_sync(void) { u32 old = readl(timer_base + TIMER_CNTVAL_REG(1)); - while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3) + while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) cpu_relax(); } @@ -104,7 +106,7 @@ static int sun4i_clkevt_next_event(unsigned long evt, struct clock_event_device *unused) { sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_setup(0, evt); + sun4i_clkevt_time_setup(0, evt - TIMER_SYNC_TICKS); sun4i_clkevt_time_start(0, false); return 0; @@ -131,7 +133,7 @@ static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id) static struct irqaction sun4i_timer_irq = { .name = "sun4i_timer0", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = sun4i_timer_interrupt, .dev_id = &sun4i_clockevent, }; @@ -187,8 +189,8 @@ static void __init sun4i_timer_init(struct device_node *node) sun4i_clockevent.cpumask = cpumask_of(0); - clockevents_config_and_register(&sun4i_clockevent, rate, 0x1, - 0xffffffff); + clockevents_config_and_register(&sun4i_clockevent, rate, + TIMER_SYNC_TICKS, 0xffffffff); } CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer", sun4i_timer_init); diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 8a6187225dd..00fdd117028 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -100,7 +100,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); - clk_disable(tcd->clk); + clk_disable_unprepare(tcd->clk); } switch (m) { @@ -109,7 +109,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) * of oneshot, we get lower overhead and improved accuracy. */ case CLOCK_EVT_MODE_PERIODIC: - clk_enable(tcd->clk); + clk_prepare_enable(tcd->clk); /* slow clock, count up to RC, then irq and restart */ __raw_writel(timer_clock @@ -126,7 +126,7 @@ static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) break; case CLOCK_EVT_MODE_ONESHOT: - clk_enable(tcd->clk); + clk_prepare_enable(tcd->clk); /* slow clock, count up to RC, then irq and stop */ __raw_writel(timer_clock | ATMEL_TC_CPCSTOP @@ -180,15 +180,22 @@ static irqreturn_t ch2_irq(int irq, void *handle) static struct irqaction tc_irqaction = { .name = "tc_clkevt", - .flags = IRQF_TIMER | IRQF_DISABLED, + .flags = IRQF_TIMER, .handler = ch2_irq, }; -static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) { + int ret; struct clk *t2_clk = tc->clk[2]; int irq = tc->irq[2]; + /* try to enable t2 clk to avoid future errors in mode change */ + ret = clk_prepare_enable(t2_clk); + if (ret) + return ret; + clk_disable_unprepare(t2_clk); + clkevt.regs = tc->regs; clkevt.clk = t2_clk; tc_irqaction.dev_id = &clkevt; @@ -197,16 +204,21 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) clkevt.clkevt.cpumask = cpumask_of(0); + ret = setup_irq(irq, &tc_irqaction); + if (ret) + return ret; + clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); - setup_irq(irq, &tc_irqaction); + return ret; } #else /* !CONFIG_GENERIC_CLOCKEVENTS */ -static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) +static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) { /* NOTHING */ + return 0; } #endif @@ -265,6 +277,7 @@ static int __init tcb_clksrc_init(void) int best_divisor_idx = -1; int clk32k_divisor_idx = -1; int i; + int ret; tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name); if (!tc) { @@ -275,7 +288,11 @@ static int __init tcb_clksrc_init(void) pdev = tc->pdev; t0_clk = tc->clk[0]; - clk_enable(t0_clk); + ret = clk_prepare_enable(t0_clk); + if (ret) { + pr_debug("can't enable T0 clk\n"); + goto err_free_tc; + } /* How fast will we be counting? Pick something over 5 MHz. */ rate = (u32) clk_get_rate(t0_clk); @@ -313,17 +330,39 @@ static int __init tcb_clksrc_init(void) /* tclib will give us three clocks no matter what the * underlying platform supports. */ - clk_enable(tc->clk[1]); + ret = clk_prepare_enable(tc->clk[1]); + if (ret) { + pr_debug("can't enable T1 clk\n"); + goto err_disable_t0; + } /* setup both channel 0 & 1 */ tcb_setup_dual_chan(tc, best_divisor_idx); } /* and away we go! */ - clocksource_register_hz(&clksrc, divided_rate); + ret = clocksource_register_hz(&clksrc, divided_rate); + if (ret) + goto err_disable_t1; /* channel 2: periodic and oneshot timer support */ - setup_clkevents(tc, clk32k_divisor_idx); + ret = setup_clkevents(tc, clk32k_divisor_idx); + if (ret) + goto err_unregister_clksrc; return 0; + +err_unregister_clksrc: + clocksource_unregister(&clksrc); + +err_disable_t1: + if (!tc->tcb_config || tc->tcb_config->counter_width != 32) + clk_disable_unprepare(tc->clk[1]); + +err_disable_t0: + clk_disable_unprepare(t0_clk); + +err_free_tc: + atmel_tc_free(tc); + return ret; } arch_initcall(tcb_clksrc_init); diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 93961703b88..642849256d8 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -98,7 +98,7 @@ static struct clock_event_device tegra_clockevent = { .set_mode = tegra_timer_set_mode, }; -static u32 notrace tegra_read_sched_clock(void) +static u64 notrace tegra_read_sched_clock(void) { return timer_readl(TIMERUS_CNTR_1US); } @@ -181,8 +181,6 @@ static void __init tegra20_init_timer(struct device_node *np) rate = clk_get_rate(clk); } - of_node_put(np); - switch (rate) { case 12000000: timer_writel(0x000b, TIMERUS_USEC_CFG); @@ -200,7 +198,7 @@ static void __init tegra20_init_timer(struct device_node *np) WARN(1, "Unknown clock rate"); } - setup_sched_clock(tegra_read_sched_clock, 32, 1000000); + sched_clock_register(tegra_read_sched_clock, 32, 1000000); if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { @@ -241,8 +239,6 @@ static void __init tegra20_init_rtc(struct device_node *np) else clk_prepare_enable(clk); - of_node_put(np); - register_persistent_clock(NULL, tegra_read_persistent_clock); } CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 0198504ef6b..d8e47e50278 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -96,7 +96,7 @@ static void local_timer_ctrl_clrset(u32 clr, u32 set) local_base + TIMER_CTRL_OFF); } -static u32 notrace armada_370_xp_read_sched_clock(void) +static u64 notrace armada_370_xp_read_sched_clock(void) { return ~readl(timer_base + TIMER0_VAL_OFF); } @@ -258,7 +258,7 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np) /* * Set scale and timer for sched_clock. */ - setup_sched_clock(armada_370_xp_read_sched_clock, 32, timer_clk); + sched_clock_register(armada_370_xp_read_sched_clock, 32, timer_clk); /* * Setup free-running clocksource timer (interrupts diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c new file mode 100644 index 00000000000..1a6205b7bed --- /dev/null +++ b/drivers/clocksource/time-efm32.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2013 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/clk.h> + +#define TIMERn_CTRL 0x00 +#define TIMERn_CTRL_PRESC(val) (((val) & 0xf) << 24) +#define TIMERn_CTRL_PRESC_1024 TIMERn_CTRL_PRESC(10) +#define TIMERn_CTRL_CLKSEL(val) (((val) & 0x3) << 16) +#define TIMERn_CTRL_CLKSEL_PRESCHFPERCLK TIMERn_CTRL_CLKSEL(0) +#define TIMERn_CTRL_OSMEN 0x00000010 +#define TIMERn_CTRL_MODE(val) (((val) & 0x3) << 0) +#define TIMERn_CTRL_MODE_UP TIMERn_CTRL_MODE(0) +#define TIMERn_CTRL_MODE_DOWN TIMERn_CTRL_MODE(1) + +#define TIMERn_CMD 0x04 +#define TIMERn_CMD_START 0x00000001 +#define TIMERn_CMD_STOP 0x00000002 + +#define TIMERn_IEN 0x0c +#define TIMERn_IF 0x10 +#define TIMERn_IFS 0x14 +#define TIMERn_IFC 0x18 +#define TIMERn_IRQ_UF 0x00000002 + +#define TIMERn_TOP 0x1c +#define TIMERn_CNT 0x24 + +struct efm32_clock_event_ddata { + struct clock_event_device evtdev; + void __iomem *base; + unsigned periodic_top; +}; + +static void efm32_clock_event_set_mode(enum clock_event_mode mode, + struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); + break; + + case CLOCK_EVT_MODE_ONESHOT: + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_OSMEN | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + break; + + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + break; + + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static int efm32_clock_event_set_next_event(unsigned long evt, + struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(evt, ddata->base + TIMERn_CNT); + writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); + + return 0; +} + +static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id) +{ + struct efm32_clock_event_ddata *ddata = dev_id; + + writel_relaxed(TIMERn_IRQ_UF, ddata->base + TIMERn_IFC); + + ddata->evtdev.event_handler(&ddata->evtdev); + + return IRQ_HANDLED; +} + +static struct efm32_clock_event_ddata clock_event_ddata = { + .evtdev = { + .name = "efm32 clockevent", + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_MODE_PERIODIC, + .set_mode = efm32_clock_event_set_mode, + .set_next_event = efm32_clock_event_set_next_event, + .rating = 200, + }, +}; + +static struct irqaction efm32_clock_event_irq = { + .name = "efm32 clockevent", + .flags = IRQF_TIMER, + .handler = efm32_clock_event_handler, + .dev_id = &clock_event_ddata, +}; + +static int __init efm32_clocksource_init(struct device_node *np) +{ + struct clk *clk; + void __iomem *base; + unsigned long rate; + int ret; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + pr_err("failed to get clock for clocksource (%d)\n", ret); + goto err_clk_get; + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("failed to enable timer clock for clocksource (%d)\n", + ret); + goto err_clk_enable; + } + rate = clk_get_rate(clk); + + base = of_iomap(np, 0); + if (!base) { + ret = -EADDRNOTAVAIL; + pr_err("failed to map registers for clocksource\n"); + goto err_iomap; + } + + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_MODE_UP, base + TIMERn_CTRL); + writel_relaxed(TIMERn_CMD_START, base + TIMERn_CMD); + + ret = clocksource_mmio_init(base + TIMERn_CNT, "efm32 timer", + DIV_ROUND_CLOSEST(rate, 1024), 200, 16, + clocksource_mmio_readl_up); + if (ret) { + pr_err("failed to init clocksource (%d)\n", ret); + goto err_clocksource_init; + } + + return 0; + +err_clocksource_init: + + iounmap(base); +err_iomap: + + clk_disable_unprepare(clk); +err_clk_enable: + + clk_put(clk); +err_clk_get: + + return ret; +} + +static int __init efm32_clockevent_init(struct device_node *np) +{ + struct clk *clk; + void __iomem *base; + unsigned long rate; + int irq; + int ret; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + pr_err("failed to get clock for clockevent (%d)\n", ret); + goto err_clk_get; + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("failed to enable timer clock for clockevent (%d)\n", + ret); + goto err_clk_enable; + } + rate = clk_get_rate(clk); + + base = of_iomap(np, 0); + if (!base) { + ret = -EADDRNOTAVAIL; + pr_err("failed to map registers for clockevent\n"); + goto err_iomap; + } + + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + ret = -ENOENT; + pr_err("failed to get irq for clockevent\n"); + goto err_get_irq; + } + + writel_relaxed(TIMERn_IRQ_UF, base + TIMERn_IEN); + + clock_event_ddata.base = base; + clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ); + + setup_irq(irq, &efm32_clock_event_irq); + + clockevents_config_and_register(&clock_event_ddata.evtdev, + DIV_ROUND_CLOSEST(rate, 1024), + 0xf, 0xffff); + + return 0; + +err_get_irq: + + iounmap(base); +err_iomap: + + clk_disable_unprepare(clk); +err_clk_enable: + + clk_put(clk); +err_clk_get: + + return ret; +} + +/* + * This function asserts that we have exactly one clocksource and one + * clock_event_device in the end. + */ +static void __init efm32_timer_init(struct device_node *np) +{ + static int has_clocksource, has_clockevent; + int ret; + + if (!has_clocksource) { + ret = efm32_clocksource_init(np); + if (!ret) { + has_clocksource = 1; + return; + } + } + + if (!has_clockevent) { + ret = efm32_clockevent_init(np); + if (!ret) { + has_clockevent = 1; + return; + } + } +} +CLOCKSOURCE_OF_DECLARE(efm32, "efm32,timer", efm32_timer_init); diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index ef3cfb269d8..8a492d34ff9 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -165,9 +165,9 @@ static struct irqaction sirfsoc_timer_irq = { }; /* Overwrite weak default sched_clock with more precise one */ -static u32 notrace sirfsoc_read_sched_clock(void) +static u64 notrace sirfsoc_read_sched_clock(void) { - return (u32)(sirfsoc_timer_read(NULL) & 0xffffffff); + return sirfsoc_timer_read(NULL); } static void __init sirfsoc_clockevent_init(void) @@ -206,7 +206,7 @@ static void __init sirfsoc_prima2_timer_init(struct device_node *np) BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE)); - setup_sched_clock(sirfsoc_read_sched_clock, 32, CLOCK_TICK_RATE); + sched_clock_register(sirfsoc_read_sched_clock, 64, CLOCK_TICK_RATE); BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq)); diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index 587e0202a70..02821b06a39 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -52,7 +52,7 @@ static inline void pit_irq_acknowledge(void) __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); } -static unsigned int pit_read_sched_clock(void) +static u64 pit_read_sched_clock(void) { return __raw_readl(clksrc_base + PITCVAL); } @@ -64,7 +64,7 @@ static int __init pit_clocksource_init(unsigned long rate) __raw_writel(~0UL, clksrc_base + PITLDVAL); __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL); - setup_sched_clock(pit_read_sched_clock, 32, rate); + sched_clock_register(pit_read_sched_clock, 32, rate); return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate, 300, 32, clocksource_mmio_readl_down); } diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 64f553f04fa..ad3c0e83a77 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -137,14 +137,12 @@ static void __init vt8500_timer_init(struct device_node *np) if (!regbase) { pr_err("%s: Missing iobase description in Device Tree\n", __func__); - of_node_put(np); return; } timer_irq = irq_of_parse_and_map(np, 0); if (!timer_irq) { pr_err("%s: Missing irq description in Device Tree\n", __func__); - of_node_put(np); return; } diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index 534e43a60d1..f4ec8145b3d 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c @@ -28,6 +28,7 @@ #include <linux/cpufreq.h> #include <linux/timer.h> #include <linux/module.h> +#include <linux/of_address.h> #include <asm/hw_irq.h> #include <asm/io.h> diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index f88e3d8f6b6..efaf6302405 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -27,6 +27,9 @@ #include <linux/dma-mapping.h> #include <linux/platform_device.h> #include <linux/init.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/slab.h> #include <asm/dcr.h> diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index b010d42a180..bc6d820812b 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -5,6 +5,9 @@ * Copyright 2008-2012 Freescale Semiconductor, Inc. */ +#include <linux/of_address.h> +#include <linux/of_irq.h> + #include "compat.h" #include "regs.h" #include "intern.h" @@ -224,7 +227,7 @@ static int caam_probe(struct platform_device *pdev) topregs = (struct caam_full __iomem *)ctrl; /* Get the IRQ of the controller (for security violations only) */ - ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL); + ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0); /* * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 105ba4da618..bdb786d5a5e 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -5,6 +5,8 @@ * Copyright 2008-2012 Freescale Semiconductor, Inc. */ +#include <linux/of_irq.h> + #include "compat.h" #include "regs.h" #include "jr.h" @@ -403,7 +405,7 @@ int caam_jr_probe(struct platform_device *pdev, struct device_node *np, dma_set_mask(jrdev, DMA_BIT_MASK(32)); /* Identify the interrupt */ - jrpriv->irq = of_irq_to_resource(np, 0, NULL); + jrpriv->irq = irq_of_parse_and_map(np, 0); /* Now do the platform independent part */ error = caam_jr_init(jrdev); /* now turn on hardware */ diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 8bdde57f6bb..e28104b4aab 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1818,7 +1818,7 @@ static int omap_sham_get_res_of(struct omap_sham_dev *dd, goto err; } - dd->irq = of_irq_to_resource(node, 0, NULL); + dd->irq = irq_of_parse_and_map(node, 0); if (!dd->irq) { dev_err(dev, "can't translate OF irq value\n"); err = -EINVAL; diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 661dc3eb1d6..6cd0e603858 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -32,6 +32,8 @@ #include <linux/interrupt.h> #include <linux/crypto.h> #include <linux/hw_random.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> #include <linux/io.h> diff --git a/drivers/dma/bestcomm/sram.c b/drivers/dma/bestcomm/sram.c index 5e2ed30ba2c..2074e0e3fa2 100644 --- a/drivers/dma/bestcomm/sram.c +++ b/drivers/dma/bestcomm/sram.c @@ -19,6 +19,7 @@ #include <linux/string.h> #include <linux/ioport.h> #include <linux/of.h> +#include <linux/of_address.h> #include <asm/io.h> #include <asm/mmu.h> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index b3f3e90054f..61517dd0d0b 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -33,6 +33,8 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmapool.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include "dmaengine.h" diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 2fe43537733..448750da440 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -39,7 +39,9 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/random.h> diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 370ff826563..e24b5ef486b 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -42,6 +42,8 @@ #include <linux/uaccess.h> #include <linux/proc_fs.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/dcr.h> #include <asm/dcr-regs.h> diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 3c9e4e98c65..b53d0de17e1 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -339,8 +339,8 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { csbase = pvt->csels[dct].csbases[csrow]; csmask = pvt->csels[dct].csmasks[csrow]; - base_bits = GENMASK(21, 31) | GENMASK(9, 15); - mask_bits = GENMASK(21, 29) | GENMASK(9, 15); + base_bits = GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9); + mask_bits = GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9); addr_shift = 4; /* @@ -352,16 +352,16 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, csbase = pvt->csels[dct].csbases[csrow]; csmask = pvt->csels[dct].csmasks[csrow >> 1]; - *base = (csbase & GENMASK(5, 15)) << 6; - *base |= (csbase & GENMASK(19, 30)) << 8; + *base = (csbase & GENMASK_ULL(15, 5)) << 6; + *base |= (csbase & GENMASK_ULL(30, 19)) << 8; *mask = ~0ULL; /* poke holes for the csmask */ - *mask &= ~((GENMASK(5, 15) << 6) | - (GENMASK(19, 30) << 8)); + *mask &= ~((GENMASK_ULL(15, 5) << 6) | + (GENMASK_ULL(30, 19) << 8)); - *mask |= (csmask & GENMASK(5, 15)) << 6; - *mask |= (csmask & GENMASK(19, 30)) << 8; + *mask |= (csmask & GENMASK_ULL(15, 5)) << 6; + *mask |= (csmask & GENMASK_ULL(30, 19)) << 8; return; } else { @@ -370,9 +370,11 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, addr_shift = 8; if (pvt->fam == 0x15) - base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); + base_bits = mask_bits = + GENMASK_ULL(30,19) | GENMASK_ULL(13,5); else - base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); + base_bits = mask_bits = + GENMASK_ULL(28,19) | GENMASK_ULL(13,5); } *base = (csbase & base_bits) << addr_shift; @@ -561,7 +563,7 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture * Programmer's Manual Volume 1 Application Programming. */ - dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base; + dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base; edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n", (unsigned long)sys_addr, (unsigned long)dram_addr); @@ -597,7 +599,7 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr) * concerning translating a DramAddr to an InputAddr. */ intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); - input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) + + input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) + (dram_addr & 0xfff); edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", @@ -849,7 +851,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) end_bit = 39; } - addr = m->addr & GENMASK(start_bit, end_bit); + addr = m->addr & GENMASK_ULL(end_bit, start_bit); /* * Erratum 637 workaround @@ -861,7 +863,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) u16 mce_nid; u8 intlv_en; - if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) + if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7) return addr; mce_nid = amd_get_nb_id(m->extcpu); @@ -871,7 +873,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) intlv_en = tmp >> 21 & 0x7; /* add [47:27] + 3 trailing bits */ - cc6_base = (tmp & GENMASK(0, 20)) << 3; + cc6_base = (tmp & GENMASK_ULL(20, 0)) << 3; /* reverse and add DramIntlvEn */ cc6_base |= intlv_en ^ 0x7; @@ -880,18 +882,18 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) cc6_base <<= 24; if (!intlv_en) - return cc6_base | (addr & GENMASK(0, 23)); + return cc6_base | (addr & GENMASK_ULL(23, 0)); amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); /* faster log2 */ - tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); + tmp_addr = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1); /* OR DramIntlvSel into bits [14:12] */ - tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; + tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9; /* add remaining [11:0] bits from original MC4_ADDR */ - tmp_addr |= addr & GENMASK(0, 11); + tmp_addr |= addr & GENMASK_ULL(11, 0); return cc6_base | tmp_addr; } @@ -952,12 +954,12 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); - pvt->ranges[range].lim.lo &= GENMASK(0, 15); + pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0); /* {[39:27],111b} */ pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; - pvt->ranges[range].lim.hi &= GENMASK(0, 7); + pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0); /* [47:40] */ pvt->ranges[range].lim.hi |= llim >> 13; @@ -1330,7 +1332,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range, chan_off = dram_base; } - return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47)); + return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23)); } /* diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index d2443cfa069..6dc1fcc25af 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -160,14 +160,6 @@ #define OFF false /* - * Create a contiguous bitmask starting at bit position @lo and ending at - * position @hi. For example - * - * GENMASK(21, 39) gives us the 64bit vector 0x000000ffffe00000. - */ -#define GENMASK(lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) - -/* * PCI-defined configuration space registers */ #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index c2eaf334b90..9ee1c76da7b 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/stop_machine.h> #include <linux/io.h> +#include <linux/of_address.h> #include <asm/machdep.h> #include <asm/cell-regs.h> diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index bb534670ec0..d5a98a45c06 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -297,15 +297,14 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, } /* Error address */ - if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { + if (mem_err->validation_bits & CPER_MEM_VALID_PA) { e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT; e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK; } /* Error grain */ - if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) { + if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK) e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK); - } /* Memory error location, mapped on e->location */ p = e->location; @@ -315,6 +314,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, p += sprintf(p, "card:%d ", mem_err->card); if (mem_err->validation_bits & CPER_MEM_VALID_MODULE) p += sprintf(p, "module:%d ", mem_err->module); + if (mem_err->validation_bits & CPER_MEM_VALID_RANK_NUMBER) + p += sprintf(p, "rank:%d ", mem_err->rank); if (mem_err->validation_bits & CPER_MEM_VALID_BANK) p += sprintf(p, "bank:%d ", mem_err->bank); if (mem_err->validation_bits & CPER_MEM_VALID_ROW) @@ -323,6 +324,15 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, p += sprintf(p, "col:%d ", mem_err->column); if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION) p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos); + if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { + const char *bank = NULL, *device = NULL; + dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device); + if (bank != NULL && device != NULL) + p += sprintf(p, "DIMM location:%s %s ", bank, device); + else + p += sprintf(p, "DIMM DMI handle: 0x%.4x ", + mem_err->mem_dev_handle); + } if (p > e->location) *(p - 1) = '\0'; diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index e04462b6075..88f60c5fecb 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -50,7 +50,7 @@ static int probed; * Get a bit field at register value <v>, from bit <lo> to bit <hi> */ #define GET_BITFIELD(v, lo, hi) \ - (((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo)) + (((v) & GENMASK_ULL(hi, lo)) >> (lo)) /* * sbridge Memory Controller Registers diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index fa0affb699b..c7e81ff8f3e 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -8,6 +8,7 @@ #include <linux/bootmem.h> #include <linux/random.h> #include <asm/dmi.h> +#include <asm/unaligned.h> /* * DMI stands for "Desktop Management Interface". It is part @@ -25,6 +26,13 @@ static int dmi_initialized; /* DMI system identification string used during boot */ static char dmi_ids_string[128] __initdata; +static struct dmi_memdev_info { + const char *device; + const char *bank; + u16 handle; +} *dmi_memdev; +static int dmi_memdev_nr; + static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; @@ -322,6 +330,42 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); } +static void __init count_mem_devices(const struct dmi_header *dm, void *v) +{ + if (dm->type != DMI_ENTRY_MEM_DEVICE) + return; + dmi_memdev_nr++; +} + +static void __init save_mem_devices(const struct dmi_header *dm, void *v) +{ + const char *d = (const char *)dm; + static int nr; + + if (dm->type != DMI_ENTRY_MEM_DEVICE) + return; + if (nr >= dmi_memdev_nr) { + pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n"); + return; + } + dmi_memdev[nr].handle = get_unaligned(&dm->handle); + dmi_memdev[nr].device = dmi_string(dm, d[0x10]); + dmi_memdev[nr].bank = dmi_string(dm, d[0x11]); + nr++; +} + +void __init dmi_memdev_walk(void) +{ + if (!dmi_available) + return; + + if (dmi_walk_early(count_mem_devices) == 0 && dmi_memdev_nr) { + dmi_memdev = dmi_alloc(sizeof(*dmi_memdev) * dmi_memdev_nr); + if (dmi_memdev) + dmi_walk_early(save_mem_devices); + } +} + /* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.5 we should pull the smbus controller info @@ -815,3 +859,20 @@ bool dmi_match(enum dmi_field f, const char *str) return !strcmp(info, str); } EXPORT_SYMBOL_GPL(dmi_match); + +void dmi_memdev_name(u16 handle, const char **bank, const char **device) +{ + int n; + + if (dmi_memdev == NULL) + return; + + for (n = 0; n < dmi_memdev_nr; n++) { + if (handle == dmi_memdev[n].handle) { + *bank = dmi_memdev[n].bank; + *device = dmi_memdev[n].device; + break; + } + } +} +EXPORT_SYMBOL_GPL(dmi_memdev_name); diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index b0fc7c79dfb..3150aa4874e 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -36,4 +36,7 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE backend for pstore by default. This setting can be overridden using the efivars module's pstore_disable parameter. +config UEFI_CPER + def_bool n + endmenu diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 99245ab5a79..9ba156d3c77 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -4,3 +4,4 @@ obj-y += efi.o vars.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o +obj-$(CONFIG_UEFI_CPER) += cper.o diff --git a/drivers/acpi/apei/cper.c b/drivers/firmware/efi/cper.c index 33dc6a00480..1491dd4f08f 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/firmware/efi/cper.c @@ -5,10 +5,10 @@ * Author: Huang Ying <ying.huang@intel.com> * * CPER is the format used to describe platform hardware error by - * various APEI tables, such as ERST, BERT and HEST etc. + * various tables, such as ERST, BERT and HEST etc. * * For more information about CPER, please refer to Appendix N of UEFI - * Specification version 2.3. + * Specification version 2.4. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version @@ -28,10 +28,12 @@ #include <linux/module.h> #include <linux/time.h> #include <linux/cper.h> +#include <linux/dmi.h> #include <linux/acpi.h> #include <linux/pci.h> #include <linux/aer.h> +#define INDENT_SP " " /* * CPER record ID need to be unique even after reboot, because record * ID is used as index for ERST storage, while CPER records from @@ -73,7 +75,7 @@ static const char *cper_severity_str(unsigned int severity) * printed, with @pfx is printed at the beginning of each line. */ void cper_print_bits(const char *pfx, unsigned int bits, - const char *strs[], unsigned int strs_size) + const char * const strs[], unsigned int strs_size) { int i, len = 0; const char *str; @@ -98,32 +100,32 @@ void cper_print_bits(const char *pfx, unsigned int bits, printk("%s\n", buf); } -static const char *cper_proc_type_strs[] = { +static const char * const cper_proc_type_strs[] = { "IA32/X64", "IA64", }; -static const char *cper_proc_isa_strs[] = { +static const char * const cper_proc_isa_strs[] = { "IA32", "IA64", "X64", }; -static const char *cper_proc_error_type_strs[] = { +static const char * const cper_proc_error_type_strs[] = { "cache error", "TLB error", "bus error", "micro-architectural error", }; -static const char *cper_proc_op_strs[] = { +static const char * const cper_proc_op_strs[] = { "unknown or generic", "data read", "data write", "instruction execution", }; -static const char *cper_proc_flag_strs[] = { +static const char * const cper_proc_flag_strs[] = { "restartable", "precise IP", "overflow", @@ -191,46 +193,58 @@ static const char *cper_mem_err_type_strs[] = { "memory sparing", "scrub corrected error", "scrub uncorrected error", + "physical memory map-out event", }; static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) { if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); - if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) + if (mem->validation_bits & CPER_MEM_VALID_PA) printk("%s""physical_address: 0x%016llx\n", pfx, mem->physical_addr); - if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) + if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) printk("%s""physical_address_mask: 0x%016llx\n", pfx, mem->physical_addr_mask); if (mem->validation_bits & CPER_MEM_VALID_NODE) - printk("%s""node: %d\n", pfx, mem->node); + pr_debug("node: %d\n", mem->node); if (mem->validation_bits & CPER_MEM_VALID_CARD) - printk("%s""card: %d\n", pfx, mem->card); + pr_debug("card: %d\n", mem->card); if (mem->validation_bits & CPER_MEM_VALID_MODULE) - printk("%s""module: %d\n", pfx, mem->module); + pr_debug("module: %d\n", mem->module); + if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) + pr_debug("rank: %d\n", mem->rank); if (mem->validation_bits & CPER_MEM_VALID_BANK) - printk("%s""bank: %d\n", pfx, mem->bank); + pr_debug("bank: %d\n", mem->bank); if (mem->validation_bits & CPER_MEM_VALID_DEVICE) - printk("%s""device: %d\n", pfx, mem->device); + pr_debug("device: %d\n", mem->device); if (mem->validation_bits & CPER_MEM_VALID_ROW) - printk("%s""row: %d\n", pfx, mem->row); + pr_debug("row: %d\n", mem->row); if (mem->validation_bits & CPER_MEM_VALID_COLUMN) - printk("%s""column: %d\n", pfx, mem->column); + pr_debug("column: %d\n", mem->column); if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) - printk("%s""bit_position: %d\n", pfx, mem->bit_pos); + pr_debug("bit_position: %d\n", mem->bit_pos); if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) - printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id); + pr_debug("requestor_id: 0x%016llx\n", mem->requestor_id); if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) - printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id); + pr_debug("responder_id: 0x%016llx\n", mem->responder_id); if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) - printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id); + pr_debug("target_id: 0x%016llx\n", mem->target_id); if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { u8 etype = mem->error_type; printk("%s""error_type: %d, %s\n", pfx, etype, etype < ARRAY_SIZE(cper_mem_err_type_strs) ? cper_mem_err_type_strs[etype] : "unknown"); } + if (mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { + const char *bank = NULL, *device = NULL; + dmi_memdev_name(mem->mem_dev_handle, &bank, &device); + if (bank != NULL && device != NULL) + printk("%s""DIMM location: %s %s", pfx, bank, device); + else + printk("%s""DIMM DMI handle: 0x%.4x", + pfx, mem->mem_dev_handle); + } } static const char *cper_pcie_port_type_strs[] = { @@ -248,7 +262,7 @@ static const char *cper_pcie_port_type_strs[] = { }; static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, - const struct acpi_hest_generic_data *gdata) + const struct acpi_generic_data *gdata) { if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, @@ -283,55 +297,45 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, pfx, pcie->bridge.secondary_status, pcie->bridge.control); } -static const char *apei_estatus_section_flag_strs[] = { - "primary", - "containment warning", - "reset", - "threshold exceeded", - "resource not accessible", - "latent error", -}; - -static void apei_estatus_print_section( - const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no) +static void cper_estatus_print_section( + const char *pfx, const struct acpi_generic_data *gdata, int sec_no) { uuid_le *sec_type = (uuid_le *)gdata->section_type; __u16 severity; + char newpfx[64]; severity = gdata->error_severity; - printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity, + printk("%s""Error %d, type: %s\n", pfx, sec_no, cper_severity_str(severity)); - printk("%s""flags: 0x%02x\n", pfx, gdata->flags); - cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs, - ARRAY_SIZE(apei_estatus_section_flag_strs)); if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id); if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); + snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); - printk("%s""section_type: general processor error\n", pfx); + printk("%s""section_type: general processor error\n", newpfx); if (gdata->error_data_length >= sizeof(*proc_err)) - cper_print_proc_generic(pfx, proc_err); + cper_print_proc_generic(newpfx, proc_err); else goto err_section_too_small; } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); - printk("%s""section_type: memory error\n", pfx); + printk("%s""section_type: memory error\n", newpfx); if (gdata->error_data_length >= sizeof(*mem_err)) - cper_print_mem(pfx, mem_err); + cper_print_mem(newpfx, mem_err); else goto err_section_too_small; } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { struct cper_sec_pcie *pcie = (void *)(gdata + 1); - printk("%s""section_type: PCIe error\n", pfx); + printk("%s""section_type: PCIe error\n", newpfx); if (gdata->error_data_length >= sizeof(*pcie)) - cper_print_pcie(pfx, pcie, gdata); + cper_print_pcie(newpfx, pcie, gdata); else goto err_section_too_small; } else - printk("%s""section type: unknown, %pUl\n", pfx, sec_type); + printk("%s""section type: unknown, %pUl\n", newpfx, sec_type); return; @@ -339,34 +343,38 @@ err_section_too_small: pr_err(FW_WARN "error section length is too small\n"); } -void apei_estatus_print(const char *pfx, - const struct acpi_hest_generic_status *estatus) +void cper_estatus_print(const char *pfx, + const struct acpi_generic_status *estatus) { - struct acpi_hest_generic_data *gdata; + struct acpi_generic_data *gdata; unsigned int data_len, gedata_len; int sec_no = 0; + char newpfx[64]; __u16 severity; - printk("%s""APEI generic hardware error status\n", pfx); severity = estatus->error_severity; - printk("%s""severity: %d, %s\n", pfx, severity, - cper_severity_str(severity)); + if (severity == CPER_SEV_CORRECTED) + printk("%s%s\n", pfx, + "It has been corrected by h/w " + "and requires no further action"); + printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); data_len = estatus->data_length; - gdata = (struct acpi_hest_generic_data *)(estatus + 1); - while (data_len > sizeof(*gdata)) { + gdata = (struct acpi_generic_data *)(estatus + 1); + snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); + while (data_len >= sizeof(*gdata)) { gedata_len = gdata->error_data_length; - apei_estatus_print_section(pfx, gdata, sec_no); + cper_estatus_print_section(newpfx, gdata, sec_no); data_len -= gedata_len + sizeof(*gdata); gdata = (void *)(gdata + 1) + gedata_len; sec_no++; } } -EXPORT_SYMBOL_GPL(apei_estatus_print); +EXPORT_SYMBOL_GPL(cper_estatus_print); -int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) +int cper_estatus_check_header(const struct acpi_generic_status *estatus) { if (estatus->data_length && - estatus->data_length < sizeof(struct acpi_hest_generic_data)) + estatus->data_length < sizeof(struct acpi_generic_data)) return -EINVAL; if (estatus->raw_data_length && estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) @@ -374,19 +382,19 @@ int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) return 0; } -EXPORT_SYMBOL_GPL(apei_estatus_check_header); +EXPORT_SYMBOL_GPL(cper_estatus_check_header); -int apei_estatus_check(const struct acpi_hest_generic_status *estatus) +int cper_estatus_check(const struct acpi_generic_status *estatus) { - struct acpi_hest_generic_data *gdata; + struct acpi_generic_data *gdata; unsigned int data_len, gedata_len; int rc; - rc = apei_estatus_check_header(estatus); + rc = cper_estatus_check_header(estatus); if (rc) return rc; data_len = estatus->data_length; - gdata = (struct acpi_hest_generic_data *)(estatus + 1); + gdata = (struct acpi_generic_data *)(estatus + 1); while (data_len >= sizeof(*gdata)) { gedata_len = gdata->error_data_length; if (gedata_len > data_len - sizeof(*gdata)) @@ -399,4 +407,4 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus) return 0; } -EXPORT_SYMBOL_GPL(apei_estatus_check); +EXPORT_SYMBOL_GPL(cper_estatus_check); diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c new file mode 100644 index 00000000000..b6bffbfd3be --- /dev/null +++ b/drivers/firmware/efi/efi-stub-helper.c @@ -0,0 +1,636 @@ +/* + * Helper functions used by the EFI stub on multiple + * architectures. This should be #included by the EFI stub + * implementation files. + * + * Copyright 2011 Intel Corporation; author Matt Fleming + * + * This file is part of the Linux kernel, and is made available + * under the terms of the GNU General Public License version 2. + * + */ +#define EFI_READ_CHUNK_SIZE (1024 * 1024) + +struct file_info { + efi_file_handle_t *handle; + u64 size; +}; + + + + +static void efi_char16_printk(efi_system_table_t *sys_table_arg, + efi_char16_t *str) +{ + struct efi_simple_text_output_protocol *out; + + out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out; + efi_call_phys2(out->output_string, out, str); +} + +static void efi_printk(efi_system_table_t *sys_table_arg, char *str) +{ + char *s8; + + for (s8 = str; *s8; s8++) { + efi_char16_t ch[2] = { 0 }; + + ch[0] = *s8; + if (*s8 == '\n') { + efi_char16_t nl[2] = { '\r', 0 }; + efi_char16_printk(sys_table_arg, nl); + } + + efi_char16_printk(sys_table_arg, ch); + } +} + + +static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, + efi_memory_desc_t **map, + unsigned long *map_size, + unsigned long *desc_size, + u32 *desc_ver, + unsigned long *key_ptr) +{ + efi_memory_desc_t *m = NULL; + efi_status_t status; + unsigned long key; + u32 desc_version; + + *map_size = sizeof(*m) * 32; +again: + /* + * Add an additional efi_memory_desc_t because we're doing an + * allocation which may be in a new descriptor region. + */ + *map_size += sizeof(*m); + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, + EFI_LOADER_DATA, *map_size, (void **)&m); + if (status != EFI_SUCCESS) + goto fail; + + status = efi_call_phys5(sys_table_arg->boottime->get_memory_map, + map_size, m, &key, desc_size, &desc_version); + if (status == EFI_BUFFER_TOO_SMALL) { + efi_call_phys1(sys_table_arg->boottime->free_pool, m); + goto again; + } + + if (status != EFI_SUCCESS) + efi_call_phys1(sys_table_arg->boottime->free_pool, m); + if (key_ptr && status == EFI_SUCCESS) + *key_ptr = key; + if (desc_ver && status == EFI_SUCCESS) + *desc_ver = desc_version; + +fail: + *map = m; + return status; +} + +/* + * Allocate at the highest possible address that is not above 'max'. + */ +static efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr, unsigned long max) +{ + unsigned long map_size, desc_size; + efi_memory_desc_t *map; + efi_status_t status; + unsigned long nr_pages; + u64 max_addr = 0; + int i; + + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, + NULL, NULL); + if (status != EFI_SUCCESS) + goto fail; + + /* + * Enforce minimum alignment that EFI requires when requesting + * a specific address. We are doing page-based allocations, + * so we must be aligned to a page. + */ + if (align < EFI_PAGE_SIZE) + align = EFI_PAGE_SIZE; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; +again: + for (i = 0; i < map_size / desc_size; i++) { + efi_memory_desc_t *desc; + unsigned long m = (unsigned long)map; + u64 start, end; + + desc = (efi_memory_desc_t *)(m + (i * desc_size)); + if (desc->type != EFI_CONVENTIONAL_MEMORY) + continue; + + if (desc->num_pages < nr_pages) + continue; + + start = desc->phys_addr; + end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + + if ((start + size) > end || (start + size) > max) + continue; + + if (end - size > max) + end = max; + + if (round_down(end - size, align) < start) + continue; + + start = round_down(end - size, align); + + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. + */ + if (start == 0x0) + continue; + + if (start > max_addr) + max_addr = start; + } + + if (!max_addr) + status = EFI_NOT_FOUND; + else { + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &max_addr); + if (status != EFI_SUCCESS) { + max = max_addr; + max_addr = 0; + goto again; + } + + *addr = max_addr; + } + + efi_call_phys1(sys_table_arg->boottime->free_pool, map); + +fail: + return status; +} + +/* + * Allocate at the lowest possible address. + */ +static efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, + unsigned long size, unsigned long align, + unsigned long *addr) +{ + unsigned long map_size, desc_size; + efi_memory_desc_t *map; + efi_status_t status; + unsigned long nr_pages; + int i; + + status = efi_get_memory_map(sys_table_arg, &map, &map_size, &desc_size, + NULL, NULL); + if (status != EFI_SUCCESS) + goto fail; + + /* + * Enforce minimum alignment that EFI requires when requesting + * a specific address. We are doing page-based allocations, + * so we must be aligned to a page. + */ + if (align < EFI_PAGE_SIZE) + align = EFI_PAGE_SIZE; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + for (i = 0; i < map_size / desc_size; i++) { + efi_memory_desc_t *desc; + unsigned long m = (unsigned long)map; + u64 start, end; + + desc = (efi_memory_desc_t *)(m + (i * desc_size)); + + if (desc->type != EFI_CONVENTIONAL_MEMORY) + continue; + + if (desc->num_pages < nr_pages) + continue; + + start = desc->phys_addr; + end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); + + /* + * Don't allocate at 0x0. It will confuse code that + * checks pointers against NULL. Skip the first 8 + * bytes so we start at a nice even number. + */ + if (start == 0x0) + start += 8; + + start = round_up(start, align); + if ((start + size) > end) + continue; + + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &start); + if (status == EFI_SUCCESS) { + *addr = start; + break; + } + } + + if (i == map_size / desc_size) + status = EFI_NOT_FOUND; + + efi_call_phys1(sys_table_arg->boottime->free_pool, map); +fail: + return status; +} + +static void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, + unsigned long addr) +{ + unsigned long nr_pages; + + if (!size) + return; + + nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + efi_call_phys2(sys_table_arg->boottime->free_pages, addr, nr_pages); +} + + +/* + * Check the cmdline for a LILO-style file= arguments. + * + * We only support loading a file from the same filesystem as + * the kernel image. + */ +static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + char *cmd_line, char *option_string, + unsigned long max_addr, + unsigned long *load_addr, + unsigned long *load_size) +{ + struct file_info *files; + unsigned long file_addr; + efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; + u64 file_size_total; + efi_file_io_interface_t *io; + efi_file_handle_t *fh; + efi_status_t status; + int nr_files; + char *str; + int i, j, k; + + file_addr = 0; + file_size_total = 0; + + str = cmd_line; + + j = 0; /* See close_handles */ + + if (!load_addr || !load_size) + return EFI_INVALID_PARAMETER; + + *load_addr = 0; + *load_size = 0; + + if (!str || !*str) + return EFI_SUCCESS; + + for (nr_files = 0; *str; nr_files++) { + str = strstr(str, option_string); + if (!str) + break; + + str += strlen(option_string); + + /* Skip any leading slashes */ + while (*str == '/' || *str == '\\') + str++; + + while (*str && *str != ' ' && *str != '\n') + str++; + } + + if (!nr_files) + return EFI_SUCCESS; + + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, + EFI_LOADER_DATA, + nr_files * sizeof(*files), + (void **)&files); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); + goto fail; + } + + str = cmd_line; + for (i = 0; i < nr_files; i++) { + struct file_info *file; + efi_file_handle_t *h; + efi_file_info_t *info; + efi_char16_t filename_16[256]; + unsigned long info_sz; + efi_guid_t info_guid = EFI_FILE_INFO_ID; + efi_char16_t *p; + u64 file_sz; + + str = strstr(str, option_string); + if (!str) + break; + + str += strlen(option_string); + + file = &files[i]; + p = filename_16; + + /* Skip any leading slashes */ + while (*str == '/' || *str == '\\') + str++; + + while (*str && *str != ' ' && *str != '\n') { + if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) + break; + + if (*str == '/') { + *p++ = '\\'; + str++; + } else { + *p++ = *str++; + } + } + + *p = '\0'; + + /* Only open the volume once. */ + if (!i) { + efi_boot_services_t *boottime; + + boottime = sys_table_arg->boottime; + + status = efi_call_phys3(boottime->handle_protocol, + image->device_handle, &fs_proto, + (void **)&io); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); + goto free_files; + } + + status = efi_call_phys2(io->open_volume, io, &fh); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to open volume\n"); + goto free_files; + } + } + + status = efi_call_phys5(fh->open, fh, &h, filename_16, + EFI_FILE_MODE_READ, (u64)0); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to open file: "); + efi_char16_printk(sys_table_arg, filename_16); + efi_printk(sys_table_arg, "\n"); + goto close_handles; + } + + file->handle = h; + + info_sz = 0; + status = efi_call_phys4(h->get_info, h, &info_guid, + &info_sz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + efi_printk(sys_table_arg, "Failed to get file info size\n"); + goto close_handles; + } + +grow: + status = efi_call_phys3(sys_table_arg->boottime->allocate_pool, + EFI_LOADER_DATA, info_sz, + (void **)&info); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); + goto close_handles; + } + + status = efi_call_phys4(h->get_info, h, &info_guid, + &info_sz, info); + if (status == EFI_BUFFER_TOO_SMALL) { + efi_call_phys1(sys_table_arg->boottime->free_pool, + info); + goto grow; + } + + file_sz = info->file_size; + efi_call_phys1(sys_table_arg->boottime->free_pool, info); + + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to get file info\n"); + goto close_handles; + } + + file->size = file_sz; + file_size_total += file_sz; + } + + if (file_size_total) { + unsigned long addr; + + /* + * Multiple files need to be at consecutive addresses in memory, + * so allocate enough memory for all the files. This is used + * for loading multiple files. + */ + status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, + &file_addr, max_addr); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); + goto close_handles; + } + + /* We've run out of free low memory. */ + if (file_addr > max_addr) { + efi_printk(sys_table_arg, "We've run out of free low memory\n"); + status = EFI_INVALID_PARAMETER; + goto free_file_total; + } + + addr = file_addr; + for (j = 0; j < nr_files; j++) { + unsigned long size; + + size = files[j].size; + while (size) { + unsigned long chunksize; + if (size > EFI_READ_CHUNK_SIZE) + chunksize = EFI_READ_CHUNK_SIZE; + else + chunksize = size; + status = efi_call_phys3(fh->read, + files[j].handle, + &chunksize, + (void *)addr); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to read file\n"); + goto free_file_total; + } + addr += chunksize; + size -= chunksize; + } + + efi_call_phys1(fh->close, files[j].handle); + } + + } + + efi_call_phys1(sys_table_arg->boottime->free_pool, files); + + *load_addr = file_addr; + *load_size = file_size_total; + + return status; + +free_file_total: + efi_free(sys_table_arg, file_size_total, file_addr); + +close_handles: + for (k = j; k < i; k++) + efi_call_phys1(fh->close, files[k].handle); +free_files: + efi_call_phys1(sys_table_arg->boottime->free_pool, files); +fail: + *load_addr = 0; + *load_size = 0; + + return status; +} +/* + * Relocate a kernel image, either compressed or uncompressed. + * In the ARM64 case, all kernel images are currently + * uncompressed, and as such when we relocate it we need to + * allocate additional space for the BSS segment. Any low + * memory that this function should avoid needs to be + * unavailable in the EFI memory map, as if the preferred + * address is not available the lowest available address will + * be used. + */ +static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, + unsigned long *image_addr, + unsigned long image_size, + unsigned long alloc_size, + unsigned long preferred_addr, + unsigned long alignment) +{ + unsigned long cur_image_addr; + unsigned long new_addr = 0; + efi_status_t status; + unsigned long nr_pages; + efi_physical_addr_t efi_addr = preferred_addr; + + if (!image_addr || !image_size || !alloc_size) + return EFI_INVALID_PARAMETER; + if (alloc_size < image_size) + return EFI_INVALID_PARAMETER; + + cur_image_addr = *image_addr; + + /* + * The EFI firmware loader could have placed the kernel image + * anywhere in memory, but the kernel has restrictions on the + * max physical address it can run at. Some architectures + * also have a prefered address, so first try to relocate + * to the preferred address. If that fails, allocate as low + * as possible while respecting the required alignment. + */ + nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + status = efi_call_phys4(sys_table_arg->boottime->allocate_pages, + EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, + nr_pages, &efi_addr); + new_addr = efi_addr; + /* + * If preferred address allocation failed allocate as low as + * possible. + */ + if (status != EFI_SUCCESS) { + status = efi_low_alloc(sys_table_arg, alloc_size, alignment, + &new_addr); + } + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); + return status; + } + + /* + * We know source/dest won't overlap since both memory ranges + * have been allocated by UEFI, so we can safely use memcpy. + */ + memcpy((void *)new_addr, (void *)cur_image_addr, image_size); + + /* Return the new address of the relocated image. */ + *image_addr = new_addr; + + return status; +} + +/* + * Convert the unicode UEFI command line to ASCII to pass to kernel. + * Size of memory allocated return in *cmd_line_len. + * Returns NULL on error. + */ +static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg, + efi_loaded_image_t *image, + int *cmd_line_len) +{ + u16 *s2; + u8 *s1 = NULL; + unsigned long cmdline_addr = 0; + int load_options_size = image->load_options_size / 2; /* ASCII */ + void *options = image->load_options; + int options_size = 0; + efi_status_t status; + int i; + u16 zero = 0; + + if (options) { + s2 = options; + while (*s2 && *s2 != '\n' && options_size < load_options_size) { + s2++; + options_size++; + } + } + + if (options_size == 0) { + /* No command line options, so return empty string*/ + options_size = 1; + options = &zero; + } + + options_size++; /* NUL termination */ +#ifdef CONFIG_ARM + /* + * For ARM, allocate at a high address to avoid reserved + * regions at low addresses that we don't know the specfics of + * at the time we are processing the command line. + */ + status = efi_high_alloc(sys_table_arg, options_size, 0, + &cmdline_addr, 0xfffff000); +#else + status = efi_low_alloc(sys_table_arg, options_size, 0, + &cmdline_addr); +#endif + if (status != EFI_SUCCESS) + return NULL; + + s1 = (u8 *)cmdline_addr; + s2 = (u16 *)options; + + for (i = 0; i < options_size - 1; i++) + *s1++ = *s2++; + + *s1 = '\0'; + + *cmd_line_len = options_size; + return (char *)cmdline_addr; +} diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 5145fa344ad..2e2fbdec084 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -13,11 +13,27 @@ * This file is released under the GPLv2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kobject.h> #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/efi.h> +#include <linux/io.h> + +struct efi __read_mostly efi = { + .mps = EFI_INVALID_TABLE_ADDR, + .acpi = EFI_INVALID_TABLE_ADDR, + .acpi20 = EFI_INVALID_TABLE_ADDR, + .smbios = EFI_INVALID_TABLE_ADDR, + .sal_systab = EFI_INVALID_TABLE_ADDR, + .boot_info = EFI_INVALID_TABLE_ADDR, + .hcdp = EFI_INVALID_TABLE_ADDR, + .uga = EFI_INVALID_TABLE_ADDR, + .uv_systab = EFI_INVALID_TABLE_ADDR, +}; +EXPORT_SYMBOL(efi); static struct kobject *efi_kobj; static struct kobject *efivars_kobj; @@ -132,3 +148,127 @@ err_put: } subsys_initcall(efisubsys_init); + + +/* + * We can't ioremap data in EFI boot services RAM, because we've already mapped + * it as RAM. So, look it up in the existing EFI memory map instead. Only + * callable after efi_enter_virtual_mode and before efi_free_boot_services. + */ +void __iomem *efi_lookup_mapped_addr(u64 phys_addr) +{ + struct efi_memory_map *map; + void *p; + map = efi.memmap; + if (!map) + return NULL; + if (WARN_ON(!map->map)) + return NULL; + for (p = map->map; p < map->map_end; p += map->desc_size) { + efi_memory_desc_t *md = p; + u64 size = md->num_pages << EFI_PAGE_SHIFT; + u64 end = md->phys_addr + size; + if (!(md->attribute & EFI_MEMORY_RUNTIME) && + md->type != EFI_BOOT_SERVICES_CODE && + md->type != EFI_BOOT_SERVICES_DATA) + continue; + if (!md->virt_addr) + continue; + if (phys_addr >= md->phys_addr && phys_addr < end) { + phys_addr += md->virt_addr - md->phys_addr; + return (__force void __iomem *)(unsigned long)phys_addr; + } + } + return NULL; +} + +static __initdata efi_config_table_type_t common_tables[] = { + {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20}, + {ACPI_TABLE_GUID, "ACPI", &efi.acpi}, + {HCDP_TABLE_GUID, "HCDP", &efi.hcdp}, + {MPS_TABLE_GUID, "MPS", &efi.mps}, + {SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab}, + {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios}, + {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, + {NULL_GUID, NULL, 0}, +}; + +static __init int match_config_table(efi_guid_t *guid, + unsigned long table, + efi_config_table_type_t *table_types) +{ + u8 str[EFI_VARIABLE_GUID_LEN + 1]; + int i; + + if (table_types) { + efi_guid_unparse(guid, str); + + for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) { + efi_guid_unparse(&table_types[i].guid, str); + + if (!efi_guidcmp(*guid, table_types[i].guid)) { + *(table_types[i].ptr) = table; + pr_cont(" %s=0x%lx ", + table_types[i].name, table); + return 1; + } + } + } + + return 0; +} + +int __init efi_config_init(efi_config_table_type_t *arch_tables) +{ + void *config_tables, *tablep; + int i, sz; + + if (efi_enabled(EFI_64BIT)) + sz = sizeof(efi_config_table_64_t); + else + sz = sizeof(efi_config_table_32_t); + + /* + * Let's see what config tables the firmware passed to us. + */ + config_tables = early_memremap(efi.systab->tables, + efi.systab->nr_tables * sz); + if (config_tables == NULL) { + pr_err("Could not map Configuration table!\n"); + return -ENOMEM; + } + + tablep = config_tables; + pr_info(""); + for (i = 0; i < efi.systab->nr_tables; i++) { + efi_guid_t guid; + unsigned long table; + + if (efi_enabled(EFI_64BIT)) { + u64 table64; + guid = ((efi_config_table_64_t *)tablep)->guid; + table64 = ((efi_config_table_64_t *)tablep)->table; + table = table64; +#ifndef CONFIG_64BIT + if (table64 >> 32) { + pr_cont("\n"); + pr_err("Table located above 4GB, disabling EFI.\n"); + early_iounmap(config_tables, + efi.systab->nr_tables * sz); + return -EINVAL; + } +#endif + } else { + guid = ((efi_config_table_32_t *)tablep)->guid; + table = ((efi_config_table_32_t *)tablep)->table; + } + + if (!match_config_table(&guid, table, common_tables)) + match_config_table(&guid, table, arch_tables); + + tablep += sz; + } + pr_cont("\n"); + early_iounmap(config_tables, efi.systab->nr_tables * sz); + return 0; +} diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 8a7432a4b41..933eb027d52 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -564,7 +564,7 @@ static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) return 0; } -void efivars_sysfs_exit(void) +static void efivars_sysfs_exit(void) { /* Remove all entries and destroy */ __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b6ed304863e..0f0444475bf 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -30,10 +30,6 @@ config ARCH_REQUIRE_GPIOLIB Selecting this from the architecture code will cause the gpiolib code to always get built in. -config GPIO_DEVRES - def_bool y - depends on HAS_IOMEM - menuconfig GPIOLIB bool "GPIO Support" @@ -47,6 +43,10 @@ menuconfig GPIOLIB if GPIOLIB +config GPIO_DEVRES + def_bool y + depends on HAS_IOMEM + config OF_GPIO def_bool y depends on OF @@ -129,7 +129,7 @@ config GPIO_IT8761E config GPIO_EM tristate "Emma Mobile GPIO" - depends on ARM + depends on ARM && OF_GPIO help Say yes here to support GPIO on Renesas Emma Mobile SoCs. @@ -213,7 +213,7 @@ config GPIO_OCTEON config GPIO_PL061 bool "PrimeCell PL061 GPIO support" - depends on ARM && ARM_AMBA + depends on ARM_AMBA select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device @@ -320,6 +320,15 @@ config GPIO_ICH If unsure, say N. +config GPIO_IOP + tristate "Intel IOP GPIO" + depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) + help + Say yes here to support the GPIO functionality of a number of Intel + IOP32X or IOP33X. + + If unsure, say N. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on PCI @@ -360,6 +369,10 @@ config GPIO_GRGPIO Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB VHDL IP core library. +config GPIO_TB10X + bool + select OF_GPIO + comment "I2C GPIO expanders:" config GPIO_ARIZONA @@ -612,12 +625,12 @@ config GPIO_AMD8111 If unsure, say N -config GPIO_LANGWELL - bool "Intel Langwell/Penwell GPIO support" +config GPIO_INTEL_MID + bool "Intel Mid GPIO support" depends on PCI && X86 select IRQ_DOMAIN help - Say Y here to support Intel Langwell/Penwell GPIO. + Say Y here to support Intel Mid GPIO. config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" @@ -703,7 +716,7 @@ config GPIO_74X164 comment "AC97 GPIO expanders:" config GPIO_UCB1400 - bool "Philips UCB1400 GPIO" + tristate "Philips UCB1400 GPIO" depends on UCB1400_CORE help This enables support for the Philips UCB1400 GPIO pins. @@ -759,6 +772,12 @@ config GPIO_MSIC Enable support for GPIO on intel MSIC controllers found in intel MID devices +config GPIO_BCM_KONA + bool "Broadcom Kona GPIO" + depends on OF_GPIO + help + Turn on GPIO support for Broadcom "Kona" chips. + comment "USB GPIO expanders:" config GPIO_VIPERBOARD diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 98e23ebba2c..7971e36b8b1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o @@ -28,11 +29,12 @@ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o +obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o -obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o +obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o @@ -71,6 +73,7 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o +obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 3e7812f0405..307464fd015 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -15,10 +15,95 @@ */ #include <linux/module.h> +#include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/device.h> #include <linux/gfp.h> +static void devm_gpiod_release(struct device *dev, void *res) +{ + struct gpio_desc **desc = res; + + gpiod_put(*desc); +} + +static int devm_gpiod_match(struct device *dev, void *res, void *data) +{ + struct gpio_desc **this = res, **gpio = data; + + return *this == *gpio; +} + +/** + * devm_gpiod_get - Resource-managed gpiod_get() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Managed gpiod_get(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get() for detailed + * information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, + const char *con_id) +{ + return devm_gpiod_get_index(dev, con_id, 0); +} +EXPORT_SYMBOL(devm_gpiod_get); + +/** + * devm_gpiod_get_index - Resource-managed gpiod_get_index() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * + * Managed gpiod_get_index(). GPIO descriptors returned from this function are + * automatically disposed on driver detach. See gpiod_get_index() for detailed + * information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + struct gpio_desc **dr; + struct gpio_desc *desc; + + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *), + GFP_KERNEL); + if (!dr) + return ERR_PTR(-ENOMEM); + + desc = gpiod_get_index(dev, con_id, idx); + if (IS_ERR(desc)) { + devres_free(dr); + return desc; + } + + *dr = desc; + devres_add(dev, dr); + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_index); + +/** + * devm_gpiod_put - Resource-managed gpiod_put() + * @desc: GPIO descriptor to dispose of + * + * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or + * devm_gpiod_get_index(). Normally this function will not be called as the GPIO + * will be disposed of by the resource management code. + */ +void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) +{ + WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match, + &desc)); +} +EXPORT_SYMBOL(devm_gpiod_put); + + + + static void devm_gpio_release(struct device *dev, void *res) { unsigned *gpio = res; diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 5d518d5db7a..1e04bf91328 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -176,7 +176,6 @@ static int gen_74x164_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&chip->lock); return ret; } @@ -190,8 +189,6 @@ static int gen_74x164_remove(struct spi_device *spi) if (chip == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&chip->gpio_chip); if (!ret) mutex_destroy(&chip->lock); @@ -212,7 +209,7 @@ static struct spi_driver gen_74x164_driver = { .driver = { .name = "74x164", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(gen_74x164_dt_ids), + .of_match_table = gen_74x164_dt_ids, }, .probe = gen_74x164_probe, .remove = gen_74x164_remove, diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index c0f3fc44ab0..b204033acae 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data) pending &= isr & ier; for_each_set_bit(bit, &pending, 8) { - unsigned int virq; - virq = irq_find_mapping(adnp->domain, base + bit); - handle_nested_irq(virq); + unsigned int child_irq; + child_irq = irq_find_mapping(adnp->domain, base + bit); + handle_nested_irq(child_irq); } } @@ -594,7 +594,7 @@ static struct i2c_driver adnp_i2c_driver = { .driver = { .name = "gpio-adnp", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(adnp_of_match), + .of_match_table = adnp_of_match, }, .probe = adnp_i2c_probe, .remove = adnp_i2c_remove, diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index fa8b6a76276..dceb5dcf9d1 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -109,10 +109,14 @@ static int arizona_gpio_probe(struct platform_device *pdev) arizona_gpio->arizona = arizona; arizona_gpio->gpio_chip = template_chip; arizona_gpio->gpio_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + arizona_gpio->gpio_chip.of_node = arizona->dev->of_node; +#endif switch (arizona->type) { case WM5102: case WM5110: + case WM8997: arizona_gpio->gpio_chip.ngpio = 5; break; default: diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c new file mode 100644 index 00000000000..72c927dc3be --- /dev/null +++ b/drivers/gpio/gpio-bcm-kona.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2012-2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/module.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> + +#define BCM_GPIO_PASSWD 0x00a5a501 +#define GPIO_PER_BANK 32 +#define GPIO_MAX_BANK_NUM 8 + +#define GPIO_BANK(gpio) ((gpio) >> 5) +#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) + +#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) +#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) +#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) +#define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2)) +#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) +#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) +#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) +#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) +#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) + +#define GPIO_GPPWR_OFFSET 0x00000520 + +#define GPIO_GPCTR0_DBR_SHIFT 5 +#define GPIO_GPCTR0_DBR_MASK 0x000001e0 + +#define GPIO_GPCTR0_ITR_SHIFT 3 +#define GPIO_GPCTR0_ITR_MASK 0x00000018 +#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001 +#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002 +#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003 + +#define GPIO_GPCTR0_IOTR_MASK 0x00000001 +#define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000 +#define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001 + +#define GPIO_GPCTR0_DB_ENABLE_MASK 0x00000100 + +#define LOCK_CODE 0xffffffff +#define UNLOCK_CODE 0x00000000 + +struct bcm_kona_gpio { + void __iomem *reg_base; + int num_bank; + spinlock_t lock; + struct gpio_chip gpio_chip; + struct irq_domain *irq_domain; + struct bcm_kona_gpio_bank *banks; + struct platform_device *pdev; +}; + +struct bcm_kona_gpio_bank { + int id; + int irq; + /* Used in the interrupt handler */ + struct bcm_kona_gpio *kona_gpio; +}; + +static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct bcm_kona_gpio, gpio_chip); +} + +static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, + int bank_id, int lockcode) +{ + writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); + writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); +} + +static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); +} + +static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, + int bank_id) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); +} + +static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + /* determine the GPIO pin direction */ + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* this function only applies to output pin */ + if (GPIO_GPCTR0_IOTR_CMD_INPUT == val) + goto out; + + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + val |= BIT(bit); + writel(val, reg_base + reg_offset); + +out: + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + /* determine the GPIO pin direction */ + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* read the GPIO bank status */ + reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ? + GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); + val = readl(reg_base + reg_offset); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + /* return the specified bit status */ + return !!(val & bit); +} + +static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_IOTR_MASK; + val |= GPIO_GPCTR0_IOTR_CMD_INPUT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_IOTR_MASK; + val |= GPIO_GPCTR0_IOTR_CMD_0UTPUT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + val |= BIT(bit); + writel(val, reg_base + reg_offset); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static int bcm_kona_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + + kona_gpio = to_kona_gpio(chip); + if (gpio >= kona_gpio->gpio_chip.ngpio) + return -ENXIO; + return irq_create_mapping(kona_gpio->irq_domain, gpio); +} + +static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, + unsigned debounce) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + u32 val, res; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = to_kona_gpio(chip); + reg_base = kona_gpio->reg_base; + /* debounce must be 1-128ms (or 0) */ + if ((debounce > 0 && debounce < 1000) || debounce > 128000) { + dev_err(chip->dev, "Debounce value %u not in range\n", + debounce); + return -EINVAL; + } + + /* calculate debounce bit value */ + if (debounce != 0) { + /* Convert to ms */ + debounce /= 1000; + /* find the MSB */ + res = fls(debounce) - 1; + /* Check if MSB-1 is set (round up or down) */ + if (res > 0 && (debounce & BIT(res - 1))) + res++; + } + + /* spin lock for read-modify-write of the GPIO register */ + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_DBR_MASK; + + if (debounce == 0) { + /* disable debounce */ + val &= ~GPIO_GPCTR0_DB_ENABLE_MASK; + } else { + val |= GPIO_GPCTR0_DB_ENABLE_MASK | + (res << GPIO_GPCTR0_DBR_SHIFT); + } + + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static struct gpio_chip template_chip = { + .label = "bcm-kona-gpio", + .owner = THIS_MODULE, + .direction_input = bcm_kona_gpio_direction_input, + .get = bcm_kona_gpio_get, + .direction_output = bcm_kona_gpio_direction_output, + .set = bcm_kona_gpio_set, + .set_debounce = bcm_kona_gpio_set_debounce, + .to_irq = bcm_kona_gpio_to_irq, + .base = 0, +}; + +static void bcm_kona_gpio_irq_ack(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_STATUS(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_STATUS(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static void bcm_kona_gpio_irq_mask(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_MASK(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_MASK(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static void bcm_kona_gpio_irq_unmask(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); + val |= BIT(bit); + writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int gpio = d->hwirq; + u32 lvl_type; + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + kona_gpio = irq_data_get_irq_chip_data(d); + reg_base = kona_gpio->reg_base; + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + lvl_type = GPIO_GPCTR0_ITR_CMD_RISING_EDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + lvl_type = GPIO_GPCTR0_ITR_CMD_FALLING_EDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + lvl_type = GPIO_GPCTR0_ITR_CMD_BOTH_EDGE; + break; + + case IRQ_TYPE_LEVEL_HIGH: + case IRQ_TYPE_LEVEL_LOW: + /* BCM GPIO doesn't support level triggering */ + default: + dev_err(kona_gpio->gpio_chip.dev, + "Invalid BCM GPIO irq type 0x%x\n", type); + return -EINVAL; + } + + spin_lock_irqsave(&kona_gpio->lock, flags); + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + val = readl(reg_base + GPIO_CONTROL(gpio)); + val &= ~GPIO_GPCTR0_ITR_MASK; + val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); + + return 0; +} + +static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg_base; + int bit, bank_id; + unsigned long sta; + struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + /* + * For bank interrupts, we can't use chip_data to store the kona_gpio + * pointer, since GIC needs it for its own purposes. Therefore, we get + * our pointer from the bank structure. + */ + reg_base = bank->kona_gpio->reg_base; + bank_id = bank->id; + bcm_kona_gpio_unlock_bank(reg_base, bank_id); + + while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & + (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { + for_each_set_bit(bit, &sta, 32) { + int hwirq = GPIO_PER_BANK * bank_id + bit; + int child_irq = + irq_find_mapping(bank->kona_gpio->irq_domain, + hwirq); + /* + * Clear interrupt before handler is called so we don't + * miss any interrupt occurred during executing them. + */ + writel(readl(reg_base + GPIO_INT_STATUS(bank_id)) | + BIT(bit), reg_base + GPIO_INT_STATUS(bank_id)); + /* Invoke interrupt handler */ + generic_handle_irq(child_irq); + } + } + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + + chained_irq_exit(chip, desc); +} + +static struct irq_chip bcm_gpio_irq_chip = { + .name = "bcm-kona-gpio", + .irq_ack = bcm_kona_gpio_irq_ack, + .irq_mask = bcm_kona_gpio_irq_mask, + .irq_unmask = bcm_kona_gpio_irq_unmask, + .irq_set_type = bcm_kona_gpio_irq_set_type, +}; + +static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { + { .compatible = "brcm,kona-gpio" }, + {} +}; + +MODULE_DEVICE_TABLE(of, bcm_kona_gpio_of_match); + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + int ret; + + ret = irq_set_chip_data(irq, d->host_data); + if (ret < 0) + return ret; + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static struct irq_domain_ops bcm_kona_irq_ops = { + .map = bcm_kona_gpio_irq_map, + .unmap = bcm_kona_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) +{ + void __iomem *reg_base; + int i; + + reg_base = kona_gpio->reg_base; + /* disable interrupts and clear status */ + for (i = 0; i < kona_gpio->num_bank; i++) { + bcm_kona_gpio_unlock_bank(reg_base, i); + writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); + writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); + bcm_kona_gpio_lock_bank(reg_base, i); + } +} + +static int bcm_kona_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct resource *res; + struct bcm_kona_gpio_bank *bank; + struct bcm_kona_gpio *kona_gpio; + struct gpio_chip *chip; + int ret; + int i; + + match = of_match_device(bcm_kona_gpio_of_match, dev); + if (!match) { + dev_err(dev, "Failed to find gpio controller\n"); + return -ENODEV; + } + + kona_gpio = devm_kzalloc(dev, sizeof(*kona_gpio), GFP_KERNEL); + if (!kona_gpio) + return -ENOMEM; + + kona_gpio->gpio_chip = template_chip; + chip = &kona_gpio->gpio_chip; + kona_gpio->num_bank = of_irq_count(dev->of_node); + if (kona_gpio->num_bank == 0) { + dev_err(dev, "Couldn't determine # GPIO banks\n"); + return -ENOENT; + } + if (kona_gpio->num_bank > GPIO_MAX_BANK_NUM) { + dev_err(dev, "Too many GPIO banks configured (max=%d)\n", + GPIO_MAX_BANK_NUM); + return -ENXIO; + } + kona_gpio->banks = devm_kzalloc(dev, + kona_gpio->num_bank * + sizeof(*kona_gpio->banks), GFP_KERNEL); + if (!kona_gpio->banks) + return -ENOMEM; + + kona_gpio->pdev = pdev; + platform_set_drvdata(pdev, kona_gpio); + chip->of_node = dev->of_node; + chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK; + + kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node, + chip->ngpio, + &bcm_kona_irq_ops, + kona_gpio); + if (!kona_gpio->irq_domain) { + dev_err(dev, "Couldn't allocate IRQ domain\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kona_gpio->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(kona_gpio->reg_base)) { + ret = -ENXIO; + goto err_irq_domain; + } + + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + bank->id = i; + bank->irq = platform_get_irq(pdev, i); + bank->kona_gpio = kona_gpio; + if (bank->irq < 0) { + dev_err(dev, "Couldn't get IRQ for bank %d", i); + ret = -ENOENT; + goto err_irq_domain; + } + } + + dev_info(&pdev->dev, "Setting up Kona GPIO\n"); + + bcm_kona_gpio_reset(kona_gpio); + + ret = gpiochip_add(chip); + if (ret < 0) { + dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret); + goto err_irq_domain; + } + for (i = 0; i < chip->ngpio; i++) { + int irq = bcm_kona_gpio_to_irq(chip, i); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, + handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + } + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + irq_set_chained_handler(bank->irq, bcm_kona_gpio_irq_handler); + irq_set_handler_data(bank->irq, bank); + } + + spin_lock_init(&kona_gpio->lock); + + return 0; + +err_irq_domain: + irq_domain_remove(kona_gpio->irq_domain); + + return ret; +} + +static struct platform_driver bcm_kona_gpio_driver = { + .driver = { + .name = "bcm-kona-gpio", + .owner = THIS_MODULE, + .of_match_table = bcm_kona_gpio_of_match, + }, + .probe = bcm_kona_gpio_probe, +}; + +module_platform_driver(bcm_kona_gpio_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 8369e71ebe4..9dfe36fd8ba 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -228,7 +228,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err_release_mem: release_mem_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - pci_set_drvdata(dev, NULL); err_disable: pci_disable_device(dev); err_freebg: @@ -252,7 +251,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) pci_resource_len(pdev, 0)); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); kfree(bg); } diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0edaf2ce926..0924f20fa47 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = { .driver = { .name = "clps711x-gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(clps711x_gpio_ids), + .of_match_table = clps711x_gpio_ids, }, .probe = clps711x_gpio_probe, .remove = clps711x_gpio_remove, diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index c6e1f086efe..ec190361bf2 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -232,16 +232,16 @@ static void em_gio_free(struct gpio_chip *chip, unsigned offset) em_gio_direction_input(chip, offset); } -static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct em_gio_priv *p = h->host_data; - pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq); + pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } @@ -319,6 +319,7 @@ static int em_gio_probe(struct platform_device *pdev) } gpio_chip = &p->gpio_chip; + gpio_chip->of_node = pdev->dev.of_node; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; gpio_chip->direction_output = em_gio_direction_output; diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 56b98eebe1f..80829f3c654 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port) { BUG_ON(port > 2); - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port])); - __raw_writeb(gpio_int_type2[port], + writeb_relaxed(gpio_int_type2[port], EP93XX_GPIO_REG(int_type2_register_offset[port])); - __raw_writeb(gpio_int_type1[port], + writeb_relaxed(gpio_int_type1[port], EP93XX_GPIO_REG(int_type1_register_offset[port])); - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], + writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], EP93XX_GPIO_REG(int_en_register_offset[port])); } @@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) else gpio_int_debounce[port] &= ~port_mask; - __raw_writeb(gpio_int_debounce[port], + writeb(gpio_int_debounce[port], EP93XX_GPIO_REG(int_debounce_register_offset[port])); } @@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned char status; int i; - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); + status = readb(EP93XX_GPIO_A_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; @@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); + status = readb(EP93XX_GPIO_B_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; @@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d) ep93xx_gpio_update_int_params(port); } - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) @@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) gpio_int_unmasked[port] &= ~port_mask; ep93xx_gpio_update_int_params(port); - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask(struct irq_data *d) diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c new file mode 100644 index 00000000000..be803af658a --- /dev/null +++ b/drivers/gpio/gpio-intel-mid.c @@ -0,0 +1,471 @@ +/* + * Moorestown platform Langwell chip GPIO driver + * + * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * Moorestown platform Langwell chip. + * Medfield platform Penwell chip. + * Clovertrail platform Cloverview chip. + * Merrifield platform Tangier chip. + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/stddef.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/irqdomain.h> + +#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) +#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) + +/* + * Langwell chip has 64 pins and thus there are 2 32bit registers to control + * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit + * registers to control them, so we only define the order here instead of a + * structure, to get a bit offset for a pin (use GPDR as an example): + * + * nreg = ngpio / 32; + * reg = offset / 32; + * bit = offset % 32; + * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; + * + * so the bit of reg_addr is to control pin offset's GPDR feature +*/ + +enum GPIO_REG { + GPLR = 0, /* pin level read-only */ + GPDR, /* pin direction */ + GPSR, /* pin set */ + GPCR, /* pin clear */ + GRER, /* rising edge detect */ + GFER, /* falling edge detect */ + GEDR, /* edge detect result */ + GAFR, /* alt function */ +}; + +/* intel_mid gpio driver data */ +struct intel_mid_gpio_ddata { + u16 ngpio; /* number of gpio pins */ + u32 gplr_offset; /* offset of first GPLR register from base */ + u32 flis_base; /* base address of FLIS registers */ + u32 flis_len; /* length of FLIS registers */ + u32 (*get_flis_offset)(int gpio); + u32 chip_irq_type; /* chip interrupt type */ +}; + +struct intel_mid_gpio { + struct gpio_chip chip; + void __iomem *reg_base; + spinlock_t lock; + struct pci_dev *pdev; + struct irq_domain *domain; +}; + +#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip) + +static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 32; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 16; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static int intel_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); + u32 value = readl(gafr); + int shift = (offset % 16) << 1, af = (value >> shift) & 3; + + if (af) { + value &= ~(3 << shift); + writel(value, gafr); + } + return 0; +} + +static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gplr = gpio_reg(chip, offset, GPLR); + + return readl(gplr) & BIT(offset % 32); +} + +static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + void __iomem *gpsr, *gpcr; + + if (value) { + gpsr = gpio_reg(chip, offset, GPSR); + writel(BIT(offset % 32), gpsr); + } else { + gpcr = gpio_reg(chip, offset, GPCR); + writel(BIT(offset % 32), gpcr); + } +} + +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + u32 value; + unsigned long flags; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value &= ~BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + unsigned long flags; + + intel_gpio_set(chip, offset, value); + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value |= BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + return irq_create_mapping(priv->domain, offset); +} + +static int intel_mid_irq_type(struct irq_data *d, unsigned type) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + u32 gpio = irqd_to_hwirq(d); + unsigned long flags; + u32 value; + void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); + void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); + + if (gpio >= priv->chip.ngpio) + return -EINVAL; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + if (type & IRQ_TYPE_EDGE_RISING) + value = readl(grer) | BIT(gpio % 32); + else + value = readl(grer) & (~BIT(gpio % 32)); + writel(value, grer); + + if (type & IRQ_TYPE_EDGE_FALLING) + value = readl(gfer) | BIT(gpio % 32); + else + value = readl(gfer) & (~BIT(gpio % 32)); + writel(value, gfer); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static void intel_mid_irq_unmask(struct irq_data *d) +{ +} + +static void intel_mid_irq_mask(struct irq_data *d) +{ +} + +static struct irq_chip intel_mid_irqchip = { + .name = "INTEL_MID-GPIO", + .irq_mask = intel_mid_irq_mask, + .irq_unmask = intel_mid_irq_unmask, + .irq_set_type = intel_mid_irq_type, +}; + +static const struct intel_mid_gpio_ddata gpio_lincroft = { + .ngpio = 64, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_tangier = { + .ngpio = 192, + .gplr_offset = 4, + .flis_base = 0xff0c0000, + .flis_len = 0x8000, + .get_flis_offset = NULL, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static DEFINE_PCI_DEVICE_TABLE(intel_gpio_ids) = { + { + /* Lincroft */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), + .driver_data = (kernel_ulong_t)&gpio_lincroft, + }, + { + /* Penwell AON */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), + .driver_data = (kernel_ulong_t)&gpio_penwell_aon, + }, + { + /* Penwell Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), + .driver_data = (kernel_ulong_t)&gpio_penwell_core, + }, + { + /* Cloverview Aon */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), + .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, + }, + { + /* Cloverview Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), + .driver_data = (kernel_ulong_t)&gpio_cloverview_core, + }, + { + /* Tangier */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199), + .driver_data = (kernel_ulong_t)&gpio_tangier, + }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, intel_gpio_ids); + +static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, gpio, mask; + unsigned long pending; + void __iomem *gedr; + + /* check GPIO controller to check which pin triggered the interrupt */ + for (base = 0; base < priv->chip.ngpio; base += 32) { + gedr = gpio_reg(&priv->chip, base, GEDR); + while ((pending = readl(gedr))) { + gpio = __ffs(pending); + mask = BIT(gpio); + /* Clear before handling so we can't lose an edge */ + writel(mask, gedr); + generic_handle_irq(irq_find_mapping(priv->domain, + base + gpio)); + } + } + + chip->irq_eoi(data); +} + +static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv) +{ + void __iomem *reg; + unsigned base; + + for (base = 0; base < priv->chip.ngpio; base += 32) { + /* Clear the rising-edge detect register */ + reg = gpio_reg(&priv->chip, base, GRER); + writel(0, reg); + /* Clear the falling-edge detect register */ + reg = gpio_reg(&priv->chip, base, GFER); + writel(0, reg); + /* Clear the edge detect status register */ + reg = gpio_reg(&priv->chip, base, GEDR); + writel(~0, reg); + } +} + +static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct intel_mid_gpio *priv = d->host_data; + + irq_set_chip_and_handler_name(irq, &intel_mid_irqchip, + handle_simple_irq, "demux"); + irq_set_chip_data(irq, priv); + irq_set_irq_type(irq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops intel_gpio_irq_ops = { + .map = intel_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int intel_gpio_runtime_idle(struct device *dev) +{ + pm_schedule_suspend(dev, 500); + return -EBUSY; +} + +static const struct dev_pm_ops intel_gpio_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) +}; + +static int intel_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *base; + struct intel_mid_gpio *priv; + u32 gpio_base; + u32 irq_base; + int retval; + struct intel_mid_gpio_ddata *ddata = + (struct intel_mid_gpio_ddata *)id->driver_data; + + retval = pcim_enable_device(pdev); + if (retval) + return retval; + + retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); + if (retval) { + dev_err(&pdev->dev, "I/O memory mapping error\n"); + return retval; + } + + base = pcim_iomap_table(pdev)[1]; + + irq_base = readl(base); + gpio_base = readl(sizeof(u32) + base); + + /* release the IO mapping, since we already get the info from bar1 */ + pcim_iounmap_regions(pdev, 1 << 1); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "can't allocate chip data\n"); + return -ENOMEM; + } + + priv->reg_base = pcim_iomap_table(pdev)[0]; + priv->chip.label = dev_name(&pdev->dev); + priv->chip.request = intel_gpio_request; + priv->chip.direction_input = intel_gpio_direction_input; + priv->chip.direction_output = intel_gpio_direction_output; + priv->chip.get = intel_gpio_get; + priv->chip.set = intel_gpio_set; + priv->chip.to_irq = intel_gpio_to_irq; + priv->chip.base = gpio_base; + priv->chip.ngpio = ddata->ngpio; + priv->chip.can_sleep = 0; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + + priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio, + irq_base, &intel_gpio_irq_ops, priv); + if (!priv->domain) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + retval = gpiochip_add(&priv->chip); + if (retval) { + dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); + return retval; + } + + intel_mid_irq_init_hw(priv); + + irq_set_handler_data(pdev->irq, priv); + irq_set_chained_handler(pdev->irq, intel_mid_irq_handler); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static struct pci_driver intel_gpio_driver = { + .name = "intel_mid_gpio", + .id_table = intel_gpio_ids, + .probe = intel_gpio_probe, + .driver = { + .pm = &intel_gpio_pm_ops, + }, +}; + +static int __init intel_gpio_init(void) +{ + return pci_register_driver(&intel_gpio_driver); +} + +device_initcall(intel_gpio_init); diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c new file mode 100644 index 00000000000..c22a61be3a9 --- /dev/null +++ b/drivers/gpio/gpio-iop.c @@ -0,0 +1,130 @@ +/* + * arch/arm/plat-iop/gpio.c + * GPIO handling for Intel IOP3xx processors. + * + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/export.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#define IOP3XX_N_GPIOS 8 + +#define GPIO_IN 0 +#define GPIO_OUT 1 +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +/* Memory base offset */ +static void __iomem *base; + +#define IOP3XX_GPIO_REG(reg) (base + (reg)) +#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000) +#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004) +#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008) + +static void gpio_line_config(int line, int direction) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(IOP3XX_GPOE); + if (direction == GPIO_IN) { + val |= BIT(line); + } else if (direction == GPIO_OUT) { + val &= ~BIT(line); + } + writel(val, IOP3XX_GPOE); + local_irq_restore(flags); +} + +static int gpio_line_get(int line) +{ + return !!(readl(IOP3XX_GPID) & BIT(line)); +} + +static void gpio_line_set(int line, int value) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(IOP3XX_GPOD); + if (value == GPIO_LOW) { + val &= ~BIT(line); + } else if (value == GPIO_HIGH) { + val |= BIT(line); + } + writel(val, IOP3XX_GPOD); + local_irq_restore(flags); +} + +static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + gpio_line_config(gpio, GPIO_IN); + return 0; +} + +static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +{ + gpio_line_set(gpio, level); + gpio_line_config(gpio, GPIO_OUT); + return 0; +} + +static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return gpio_line_get(gpio); +} + +static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + gpio_line_set(gpio, value); +} + +static struct gpio_chip iop3xx_chip = { + .label = "iop3xx", + .direction_input = iop3xx_gpio_direction_input, + .get = iop3xx_gpio_get_value, + .direction_output = iop3xx_gpio_direction_output, + .set = iop3xx_gpio_set_value, + .base = 0, + .ngpio = IOP3XX_N_GPIOS, +}; + +static int iop3xx_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + + return gpiochip_add(&iop3xx_chip); +} + +static struct platform_driver iop3xx_gpio_driver = { + .driver = { + .name = "gpio-iop", + .owner = THIS_MODULE, + }, + .probe = iop3xx_gpio_probe, +}; + +static int __init iop3xx_gpio_init(void) +{ + return platform_driver_register(&iop3xx_gpio_driver); +} +arch_initcall(iop3xx_gpio_init); diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c deleted file mode 100644 index bfa1af1b519..00000000000 --- a/drivers/gpio/gpio-langwell.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Moorestown platform Langwell chip GPIO driver - * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Supports: - * Moorestown platform Langwell chip. - * Medfield platform Penwell chip. - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/stddef.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/irqdomain.h> - -/* - * Langwell chip has 64 pins and thus there are 2 32bit registers to control - * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit - * registers to control them, so we only define the order here instead of a - * structure, to get a bit offset for a pin (use GPDR as an example): - * - * nreg = ngpio / 32; - * reg = offset / 32; - * bit = offset % 32; - * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; - * - * so the bit of reg_addr is to control pin offset's GPDR feature -*/ - -enum GPIO_REG { - GPLR = 0, /* pin level read-only */ - GPDR, /* pin direction */ - GPSR, /* pin set */ - GPCR, /* pin clear */ - GRER, /* rising edge detect */ - GFER, /* falling edge detect */ - GEDR, /* edge detect result */ - GAFR, /* alt function */ -}; - -struct lnw_gpio { - struct gpio_chip chip; - void __iomem *reg_base; - spinlock_t lock; - struct pci_dev *pdev; - struct irq_domain *domain; -}; - -#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) - -static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 32; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 16; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); - u32 value = readl(gafr); - int shift = (offset % 16) << 1, af = (value >> shift) & 3; - - if (af) { - value &= ~(3 << shift); - writel(value, gafr); - } - return 0; -} - -static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gplr = gpio_reg(chip, offset, GPLR); - - return readl(gplr) & BIT(offset % 32); -} - -static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *gpsr, *gpcr; - - if (value) { - gpsr = gpio_reg(chip, offset, GPSR); - writel(BIT(offset % 32), gpsr); - } else { - gpcr = gpio_reg(chip, offset, GPCR); - writel(BIT(offset % 32), gpcr); - } -} - -static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - u32 value; - unsigned long flags; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value &= ~BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - unsigned long flags; - - lnw_gpio_set(chip, offset, value); - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value |= BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - return irq_create_mapping(lnw->domain, offset); -} - -static int lnw_irq_type(struct irq_data *d, unsigned type) -{ - struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); - u32 gpio = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); - void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER); - - if (gpio >= lnw->chip.ngpio) - return -EINVAL; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - if (type & IRQ_TYPE_EDGE_RISING) - value = readl(grer) | BIT(gpio % 32); - else - value = readl(grer) & (~BIT(gpio % 32)); - writel(value, grer); - - if (type & IRQ_TYPE_EDGE_FALLING) - value = readl(gfer) | BIT(gpio % 32); - else - value = readl(gfer) & (~BIT(gpio % 32)); - writel(value, gfer); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static void lnw_irq_unmask(struct irq_data *d) -{ -} - -static void lnw_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip lnw_irqchip = { - .name = "LNW-GPIO", - .irq_mask = lnw_irq_mask, - .irq_unmask = lnw_irq_unmask, - .irq_set_type = lnw_irq_type, -}; - -static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); - -static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, mask; - unsigned long pending; - void __iomem *gedr; - - /* check GPIO controller to check which pin triggered the interrupt */ - for (base = 0; base < lnw->chip.ngpio; base += 32) { - gedr = gpio_reg(&lnw->chip, base, GEDR); - while ((pending = readl(gedr))) { - gpio = __ffs(pending); - mask = BIT(gpio); - /* Clear before handling so we can't lose an edge */ - writel(mask, gedr); - generic_handle_irq(irq_find_mapping(lnw->domain, - base + gpio)); - } - } - - chip->irq_eoi(data); -} - -static void lnw_irq_init_hw(struct lnw_gpio *lnw) -{ - void __iomem *reg; - unsigned base; - - for (base = 0; base < lnw->chip.ngpio; base += 32) { - /* Clear the rising-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GRER); - writel(0, reg); - /* Clear the falling-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GFER); - writel(0, reg); - /* Clear the edge detect status register */ - reg = gpio_reg(&lnw->chip, base, GEDR); - writel(~0, reg); - } -} - -static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - struct lnw_gpio *lnw = d->host_data; - - irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq, - "demux"); - irq_set_chip_data(virq, lnw); - irq_set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops lnw_gpio_irq_ops = { - .map = lnw_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int lnw_gpio_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static const struct dev_pm_ops lnw_gpio_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle) -}; - -static int lnw_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *base; - struct lnw_gpio *lnw; - u32 gpio_base; - u32 irq_base; - int retval; - int ngpio = id->driver_data; - - retval = pcim_enable_device(pdev); - if (retval) - return retval; - - retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); - if (retval) { - dev_err(&pdev->dev, "I/O memory mapping error\n"); - return retval; - } - - base = pcim_iomap_table(pdev)[1]; - - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); - - /* release the IO mapping, since we already get the info from bar1 */ - pcim_iounmap_regions(pdev, 1 << 1); - - lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); - if (!lnw) { - dev_err(&pdev->dev, "can't allocate chip data\n"); - return -ENOMEM; - } - - lnw->reg_base = pcim_iomap_table(pdev)[0]; - lnw->chip.label = dev_name(&pdev->dev); - lnw->chip.request = lnw_gpio_request; - lnw->chip.direction_input = lnw_gpio_direction_input; - lnw->chip.direction_output = lnw_gpio_direction_output; - lnw->chip.get = lnw_gpio_get; - lnw->chip.set = lnw_gpio_set; - lnw->chip.to_irq = lnw_gpio_to_irq; - lnw->chip.base = gpio_base; - lnw->chip.ngpio = ngpio; - lnw->chip.can_sleep = 0; - lnw->pdev = pdev; - - spin_lock_init(&lnw->lock); - - lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base, - &lnw_gpio_irq_ops, lnw); - if (!lnw->domain) - return -ENOMEM; - - pci_set_drvdata(pdev, lnw); - retval = gpiochip_add(&lnw->chip); - if (retval) { - dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); - return retval; - } - - lnw_irq_init_hw(lnw); - - irq_set_handler_data(pdev->irq, lnw); - irq_set_chained_handler(pdev->irq, lnw_irq_handler); - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static struct pci_driver lnw_gpio_driver = { - .name = "langwell_gpio", - .id_table = lnw_gpio_ids, - .probe = lnw_gpio_probe, - .driver = { - .pm = &lnw_gpio_pm_ops, - }, -}; - -static int __init lnw_gpio_init(void) -{ - return pci_register_driver(&lnw_gpio_driver); -} - -device_initcall(lnw_gpio_init); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 90a80eb688a..2d5555decf0 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 41b5913ddab..a0804740a0b 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -242,14 +242,13 @@ static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(lg->domain, offset); } -static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); struct lp_gpio *lg = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, pin, mask; unsigned long reg, ena, pending; - unsigned virq; /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { @@ -257,12 +256,14 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); while ((pending = (inl(reg) & inl(ena)))) { + unsigned irq; + pin = __ffs(pending); mask = BIT(pin); /* Clear before handling so we don't lose an edge */ outl(mask, reg); - virq = irq_find_mapping(lg->domain, base + pin); - generic_handle_irq(virq); + irq = irq_find_mapping(lg->domain, base + pin); + generic_handle_irq(irq); } } chip->irq_eoi(data); @@ -325,15 +326,15 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg) } } -static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct lp_gpio *lg = d->host_data; - irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq, "demux"); - irq_set_chip_data(virq, lg); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, lg); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 3fd2caa4a2e..c0b7835f513 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -142,7 +142,6 @@ static int mc33880_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&mc->lock); return ret; } @@ -156,8 +155,6 @@ static int mc33880_remove(struct spi_device *spi) if (mc == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&mc->chip); if (!ret) mutex_destroy(&mc->lock); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index a0b33a216d4..914e859e3ed 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -14,6 +14,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/of_irq.h> #include <linux/gpio.h> #include <linux/slab.h> #include <linux/irq.h> @@ -282,16 +283,16 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_set_type = mpc8xxx_irq_set_type, }; -static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; if (mpc8xxx_gc->of_dev_id_data) mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); return 0; } diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index f8e6af20dfb..532bcb336ef 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -254,7 +254,6 @@ static int mxs_gpio_probe(struct platform_device *pdev) struct device_node *parent; static void __iomem *base; struct mxs_gpio_port *port; - struct resource *iores = NULL; int irq_base; int err; @@ -262,16 +261,10 @@ static int mxs_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - if (np) { - port->id = of_alias_get_id(np, "gpio"); - if (port->id < 0) - return port->id; - port->devid = (enum mxs_gpio_id) of_id->data; - } else { - port->id = pdev->id; - port->devid = pdev->id_entry->driver_data; - } - + port->id = of_alias_get_id(np, "gpio"); + if (port->id < 0) + return port->id; + port->devid = (enum mxs_gpio_id) of_id->data; port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) return port->irq; @@ -281,18 +274,11 @@ static int mxs_gpio_probe(struct platform_device *pdev) * share the same one */ if (!base) { - if (np) { - parent = of_get_parent(np); - base = of_iomap(parent, 0); - of_node_put(parent); - if (!base) - return -EADDRNOTAVAIL; - } else { - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, iores); - if (IS_ERR(base)) - return PTR_ERR(base); - } + parent = of_get_parent(np); + base = of_iomap(parent, 0); + of_node_put(parent); + if (!base) + return -EADDRNOTAVAIL; } port->base = base; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 89675f86230..f319c9ffd4a 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -514,6 +514,14 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; } + retval = gpio_lock_as_irq(&bank->chip, offset); + if (retval) { + dev_err(bank->dev, "unable to lock offset %d for IRQ\n", + offset); + spin_unlock_irqrestore(&bank->lock, flags); + return retval; + } + bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -797,6 +805,7 @@ static void gpio_irq_shutdown(struct irq_data *d) unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); + gpio_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(1 << offset); _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); @@ -957,22 +966,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_bank *bank; unsigned long flags; - int retval = 0; bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - - if (LINE_USED(bank->irq_usage, offset)) { - retval = -EINVAL; - goto exit; - } - bank->set_dataout(bank, offset, value); _set_gpio_direction(bank, offset, 0); - -exit: spin_unlock_irqrestore(&bank->lock, flags); - return retval; + return 0; } static int gpio_debounce(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 8588af0f766..11801e986dd 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -31,6 +31,10 @@ struct palmas_gpio { struct palmas *palmas; }; +struct palmas_device_data { + int ngpio; +}; + static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) { return container_of(chip, struct palmas_gpio, gpio_chip); @@ -42,23 +46,26 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) struct palmas *palmas = pg->palmas; unsigned int val; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } - if (val & (1 << offset)) { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_OUT, &val); - } else { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_IN, &val); - } + if (val & BIT(offset)) + reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT; + else + reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN; + + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", - ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } return !!(val & BIT(offset)); @@ -70,17 +77,20 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); - if (value) - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_SET_DATA_OUT, BIT(offset)); + offset %= 8; + if (gpio16) + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2; else - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset)); + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT; + + ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset)); if (ret < 0) - dev_err(gc->dev, "%s write failed, err = %d\n", - (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT", - ret); + dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret); } static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, @@ -89,14 +99,19 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; /* Set the initial value */ palmas_gpio_set(gc, offset, value); - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset)); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, + BIT(offset), BIT(offset)); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -105,11 +120,15 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), 0); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -121,12 +140,36 @@ static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); } +static const struct palmas_device_data palmas_dev_data = { + .ngpio = 8, +}; + +static const struct palmas_device_data tps80036_dev_data = { + .ngpio = 16, +}; + +static struct of_device_id of_palmas_gpio_match[] = { + { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); + static int palmas_gpio_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_platform_data *palmas_pdata; struct palmas_gpio *palmas_gpio; int ret; + const struct of_device_id *match; + const struct palmas_device_data *dev_data; + + match = of_match_device(of_palmas_gpio_match, &pdev->dev); + dev_data = match->data; + if (!dev_data) + dev_data = &palmas_dev_data; palmas_gpio = devm_kzalloc(&pdev->dev, sizeof(*palmas_gpio), GFP_KERNEL); @@ -138,7 +181,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->palmas = palmas; palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); - palmas_gpio->gpio_chip.ngpio = 8; + palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; palmas_gpio->gpio_chip.can_sleep = 1; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; @@ -172,15 +215,6 @@ static int palmas_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&palmas_gpio->gpio_chip); } -static struct of_device_id of_palmas_gpio_match[] = { - { .compatible = "ti,palmas-gpio"}, - { .compatible = "ti,tps65913-gpio"}, - { .compatible = "ti,tps65914-gpio"}, - { .compatible = "ti,tps80036-gpio"}, - { }, -}; -MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); - static struct platform_driver palmas_gpio_driver = { .driver.name = "palmas-gpio", .driver.owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cdd1aa12b89..6e48c07e3d8 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -683,17 +683,6 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) int ret; u8 val[MAX_BANK]; - /* Let every port in proper state, that could save power */ - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_PUPD, val); - memset(val, 0xFF, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_CFG, val); - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_OUT, val); - - ret = pca953x_read_regs(chip, PCA957X_IN, val); - if (ret) - goto out; ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); if (ret) goto out; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 9e61bb0719d..1535686e74e 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -26,9 +26,10 @@ #include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/workqueue.h> static const struct i2c_device_id pcf857x_id[] = { @@ -50,6 +51,27 @@ static const struct i2c_device_id pcf857x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); +#ifdef CONFIG_OF +static const struct of_device_id pcf857x_of_table[] = { + { .compatible = "nxp,pcf8574" }, + { .compatible = "nxp,pcf8574a" }, + { .compatible = "nxp,pca8574" }, + { .compatible = "nxp,pca9670" }, + { .compatible = "nxp,pca9672" }, + { .compatible = "nxp,pca9674" }, + { .compatible = "nxp,pcf8575" }, + { .compatible = "nxp,pca8575" }, + { .compatible = "nxp,pca9671" }, + { .compatible = "nxp,pca9673" }, + { .compatible = "nxp,pca9675" }, + { .compatible = "maxim,max7328" }, + { .compatible = "maxim,max7329" }, + { .compatible = "ti,tca9554" }, + { } +}; +MODULE_DEVICE_TABLE(of, pcf857x_of_table); +#endif + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -66,12 +88,11 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - struct work_struct work; /* irq demux work */ struct irq_domain *irq_domain; /* for irq demux */ spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ - int irq; /* real irq number */ + unsigned irq_mapped; /* mapped gpio irqs */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -164,48 +185,54 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); + int ret; - return irq_create_mapping(gpio->irq_domain, offset); + ret = irq_create_mapping(gpio->irq_domain, offset); + if (ret > 0) + gpio->irq_mapped |= (1 << offset); + + return ret; } -static void pcf857x_irq_demux_work(struct work_struct *work) +static irqreturn_t pcf857x_irq(int irq, void *data) { - struct pcf857x *gpio = container_of(work, - struct pcf857x, - work); + struct pcf857x *gpio = data; unsigned long change, i, status, flags; status = gpio->read(gpio->client); spin_lock_irqsave(&gpio->slock, flags); - change = gpio->status ^ status; + /* + * call the interrupt handler iff gpio is used as + * interrupt source, just to avoid bad irqs + */ + + change = ((gpio->status ^ status) & gpio->irq_mapped); for_each_set_bit(i, &change, gpio->chip.ngpio) generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); gpio->status = status; spin_unlock_irqrestore(&gpio->slock, flags); -} - -static irqreturn_t pcf857x_irq_demux(int irq, void *data) -{ - struct pcf857x *gpio = data; - - /* - * pcf857x can't read/write data here, - * since i2c data access might go to sleep. - */ - schedule_work(&gpio->work); return IRQ_HANDLED; } -static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, +static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, + struct pcf857x *gpio = domain->host_data; + + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + gpio->irq_mapped |= (1 << hw); + return 0; } @@ -218,8 +245,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) if (gpio->irq_domain) irq_domain_remove(gpio->irq_domain); - if (gpio->irq) - free_irq(gpio->irq, gpio); } static int pcf857x_irq_domain_init(struct pcf857x *gpio, @@ -230,20 +255,21 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, gpio->chip.ngpio, &pcf857x_irq_domain_ops, - NULL); + gpio); if (!gpio->irq_domain) goto fail; /* enable real irq */ - status = request_irq(client->irq, pcf857x_irq_demux, 0, - dev_name(&client->dev), gpio); + status = devm_request_threaded_irq(&client->dev, client->irq, + NULL, pcf857x_irq, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING, + dev_name(&client->dev), gpio); + if (status) goto fail; /* enable gpio_to_irq() */ - INIT_WORK(&gpio->work, pcf857x_irq_demux_work); gpio->chip.to_irq = pcf857x_to_irq; - gpio->irq = client->irq; return 0; @@ -257,14 +283,18 @@ fail: static int pcf857x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pcf857x_platform_data *pdata; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *np = client->dev.of_node; struct pcf857x *gpio; + unsigned int n_latch = 0; int status; - pdata = dev_get_platdata(&client->dev); - if (!pdata) { + if (IS_ENABLED(CONFIG_OF) && np) + of_property_read_u32(np, "lines-initial-states", &n_latch); + else if (pdata) + n_latch = pdata->n_latch; + else dev_dbg(&client->dev, "no platform data\n"); - } /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); @@ -357,11 +387,11 @@ static int pcf857x_probe(struct i2c_client *client, * may cause transient glitching since it can't know the last value * written (some pins may need to be driven low). * - * Using pdata->n_latch avoids that trouble. When left initialized - * to zero, our software copy of the "latch" then matches the chip's - * all-ones reset state. Otherwise it flags pins to be driven low. + * Using n_latch avoids that trouble. When left initialized to zero, + * our software copy of the "latch" then matches the chip's all-ones + * reset state. Otherwise it flags pins to be driven low. */ - gpio->out = pdata ? ~pdata->n_latch : ~0; + gpio->out = ~n_latch; gpio->status = gpio->out; status = gpiochip_add(&gpio->chip); @@ -423,6 +453,7 @@ static struct i2c_driver pcf857x_driver = { .driver = { .name = "pcf857x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcf857x_of_table), }, .probe = pcf857x_probe, .remove = pcf857x_remove, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 4274e2e70ef..f22f7f3e2e5 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -238,15 +238,15 @@ static struct irq_chip pl061_irqchip = { .irq_set_type = pl061_irq_type, }; -static int pl061_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +static int pl061_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct pl061_gpio *chip = d->host_data; - irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, "pl061"); - irq_set_chip_data(virq, chip); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, chip); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 6038966ab04..d3f15ae93bd 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_device.h> @@ -266,16 +267,16 @@ static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct gpio_rcar_priv *p = h->host_data; - dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq); + dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index b33bad1bb4d..2647e243d47 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -254,9 +254,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; - int virq = irq_find_mapping(stmpe_gpio->domain, line); + int child_irq = irq_find_mapping(stmpe_gpio->domain, + line); - handle_nested_irq(virq); + handle_nested_irq(child_irq); stat &= ~(1 << bit); } @@ -271,7 +272,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct stmpe_gpio *stmpe_gpio = d->host_data; @@ -279,26 +280,26 @@ static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, if (!stmpe_gpio) return -EINVAL; - irq_set_chip_data(hwirq, stmpe_gpio); - irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, + irq_set_chip_data(irq, stmpe_gpio); + irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(hwirq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(hwirq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(hwirq); + irq_set_noprobe(irq); #endif return 0; } -static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c new file mode 100644 index 00000000000..0502b9a041a --- /dev/null +++ b/drivers/gpio/gpio-tb10x.c @@ -0,0 +1,328 @@ +/* Abilis Systems MODULE DESCRIPTION + * + * Copyright (C) Abilis Systems 2013 + * + * Authors: Sascha Leuenberger <sascha.leuenberger@abilis.com> + * Christian Ruppert <christian.ruppert@abilis.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/spinlock.h> +#include <linux/bitops.h> +#include <linux/pinctrl/consumer.h> + +#define TB10X_GPIO_DIR_IN (0x00000000) +#define TB10X_GPIO_DIR_OUT (0x00000001) +#define OFFSET_TO_REG_DDR (0x00) +#define OFFSET_TO_REG_DATA (0x04) +#define OFFSET_TO_REG_INT_EN (0x08) +#define OFFSET_TO_REG_CHANGE (0x0C) +#define OFFSET_TO_REG_WRMASK (0x10) +#define OFFSET_TO_REG_INT_TYPE (0x14) + + +/** + * @spinlock: used for atomic read/modify/write of registers + * @base: register base address + * @domain: IRQ domain of GPIO generated interrupts managed by this controller + * @irq: Interrupt line of parent interrupt controller + * @gc: gpio_chip structure associated to this GPIO controller + */ +struct tb10x_gpio { + spinlock_t spinlock; + void __iomem *base; + struct irq_domain *domain; + int irq; + struct gpio_chip gc; +}; + +static inline u32 tb10x_reg_read(struct tb10x_gpio *gpio, unsigned int offs) +{ + return ioread32(gpio->base + offs); +} + +static inline void tb10x_reg_write(struct tb10x_gpio *gpio, unsigned int offs, + u32 val) +{ + iowrite32(val, gpio->base + offs); +} + +static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs, + u32 mask, u32 val) +{ + u32 r; + unsigned long flags; + + spin_lock_irqsave(&gpio->spinlock, flags); + + r = tb10x_reg_read(gpio, offs); + r = (r & ~mask) | (val & mask); + + tb10x_reg_write(gpio, offs, r); + + spin_unlock_irqrestore(&gpio->spinlock, flags); +} + +static inline struct tb10x_gpio *to_tb10x_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct tb10x_gpio, gc); +} + +static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); + int mask = BIT(offset); + int val = TB10X_GPIO_DIR_IN << offset; + + tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val); + + return 0; +} + +static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); + int val; + + val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA); + + if (val & BIT(offset)) + return 1; + else + return 0; +} + +static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); + int mask = BIT(offset); + int val = value << offset; + + tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val); +} + +static int tb10x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); + int mask = BIT(offset); + int val = TB10X_GPIO_DIR_OUT << offset; + + tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val); + + return 0; +} + +static int tb10x_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void tb10x_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip); + + return irq_create_mapping(tb10x_gpio->domain, offset); +} + +static int tb10x_gpio_irq_set_type(struct irq_data *data, unsigned int type) +{ + if ((type & IRQF_TRIGGER_MASK) != IRQ_TYPE_EDGE_BOTH) { + pr_err("Only (both) edge triggered interrupts supported.\n"); + return -EINVAL; + } + + irqd_set_trigger_type(data, type); + + return IRQ_SET_MASK_OK; +} + +static irqreturn_t tb10x_gpio_irq_cascade(int irq, void *data) +{ + struct tb10x_gpio *tb10x_gpio = data; + u32 r = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_CHANGE); + u32 m = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_INT_EN); + const unsigned long bits = r & m; + int i; + + for_each_set_bit(i, &bits, 32) + generic_handle_irq(irq_find_mapping(tb10x_gpio->domain, i)); + + return IRQ_HANDLED; +} + +static int tb10x_gpio_probe(struct platform_device *pdev) +{ + struct tb10x_gpio *tb10x_gpio; + struct resource *mem; + struct device_node *dn = pdev->dev.of_node; + int ret = -EBUSY; + u32 ngpio; + + if (!dn) + return -EINVAL; + + if (of_property_read_u32(dn, "abilis,ngpio", &ngpio)) + return -EINVAL; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource defined.\n"); + return -EINVAL; + } + + tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL); + if (tb10x_gpio == NULL) + return -ENOMEM; + + spin_lock_init(&tb10x_gpio->spinlock); + + tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(tb10x_gpio->base)) + return PTR_ERR(tb10x_gpio->base); + + tb10x_gpio->gc.label = of_node_full_name(dn); + tb10x_gpio->gc.dev = &pdev->dev; + tb10x_gpio->gc.owner = THIS_MODULE; + tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in; + tb10x_gpio->gc.get = tb10x_gpio_get; + tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out; + tb10x_gpio->gc.set = tb10x_gpio_set; + tb10x_gpio->gc.request = tb10x_gpio_request; + tb10x_gpio->gc.free = tb10x_gpio_free; + tb10x_gpio->gc.base = -1; + tb10x_gpio->gc.ngpio = ngpio; + tb10x_gpio->gc.can_sleep = 0; + + + ret = gpiochip_add(&tb10x_gpio->gc); + if (ret < 0) { + dev_err(&pdev->dev, "Could not add gpiochip.\n"); + goto fail_gpiochip_registration; + } + + platform_set_drvdata(pdev, tb10x_gpio); + + if (of_find_property(dn, "interrupt-controller", NULL)) { + struct irq_chip_generic *gc; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "No interrupt specified.\n"); + goto fail_get_irq; + } + + tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq; + tb10x_gpio->irq = ret; + + ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade, + IRQF_TRIGGER_NONE | IRQF_SHARED, + dev_name(&pdev->dev), tb10x_gpio); + if (ret != 0) + goto fail_request_irq; + + tb10x_gpio->domain = irq_domain_add_linear(dn, + tb10x_gpio->gc.ngpio, + &irq_generic_chip_ops, NULL); + if (!tb10x_gpio->domain) { + ret = -ENOMEM; + goto fail_irq_domain; + } + + ret = irq_alloc_domain_generic_chips(tb10x_gpio->domain, + tb10x_gpio->gc.ngpio, 1, tb10x_gpio->gc.label, + handle_edge_irq, IRQ_NOREQUEST, IRQ_NOPROBE, + IRQ_GC_INIT_MASK_CACHE); + if (ret) + goto fail_irq_domain; + + gc = tb10x_gpio->domain->gc->gc[0]; + gc->reg_base = tb10x_gpio->base; + gc->chip_types[0].type = IRQ_TYPE_EDGE_BOTH; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = tb10x_gpio_irq_set_type; + gc->chip_types[0].regs.ack = OFFSET_TO_REG_CHANGE; + gc->chip_types[0].regs.mask = OFFSET_TO_REG_INT_EN; + } + + return 0; + +fail_irq_domain: +fail_request_irq: +fail_get_irq: + gpiochip_remove(&tb10x_gpio->gc); +fail_gpiochip_registration: +fail_ioremap: + return ret; +} + +static int __exit tb10x_gpio_remove(struct platform_device *pdev) +{ + struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev); + int ret; + + if (tb10x_gpio->gc.to_irq) { + irq_remove_generic_chip(tb10x_gpio->domain->gc->gc[0], + BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0); + kfree(tb10x_gpio->domain->gc); + irq_domain_remove(tb10x_gpio->domain); + free_irq(tb10x_gpio->irq, tb10x_gpio); + } + ret = gpiochip_remove(&tb10x_gpio->gc); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id tb10x_gpio_dt_ids[] = { + { .compatible = "abilis,tb10x-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(of, tb10x_gpio_dt_ids); + +static struct platform_driver tb10x_gpio_driver = { + .probe = tb10x_gpio_probe, + .remove = tb10x_gpio_remove, + .driver = { + .name = "tb10x-gpio", + .of_match_table = of_match_ptr(tb10x_gpio_dt_ids), + .owner = THIS_MODULE, + } +}; + +module_platform_driver(tb10x_gpio_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("tb10x gpio."); +MODULE_VERSION("0.0.1"); diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 4a5de273c23..ddb5fefaa71 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -96,27 +96,27 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, } /** - * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ * * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs + * @irq: index of the hardware interrupt requested in the chip IRQs * * Useful for drivers to request their own IRQs. */ -static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, - int irq) +static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, + int hwirq) { if (!tc3589x_gpio) return -EINVAL; - return irq_create_mapping(tc3589x_gpio->domain, irq); + return irq_create_mapping(tc3589x_gpio->domain, hwirq); } static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); + return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); } static struct gpio_chip template_chip = { @@ -242,9 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); + int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); - handle_nested_irq(virq); + handle_nested_irq(irq); stat &= ~(1 << bit); } @@ -254,31 +254,31 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct tc3589x *tc3589x_gpio = d->host_data; - irq_set_chip_data(virq, tc3589x_gpio); - irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, + irq_set_chip_data(irq, tc3589x_gpio); + irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(virq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(virq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(virq); + irq_set_noprobe(irq); #endif return 0; } -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static struct irq_domain_ops tc3589x_irq_ops = { diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9a62672f1be..cfd3b9037bc 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,6 +75,7 @@ struct tegra_gpio_bank { #endif }; +static struct device *dev; static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; @@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) int lvl_type; int val; unsigned long flags; + int ret; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio); + if (ret) { + dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio); + return ret; + } + spin_lock_irqsave(&bank->lvl_lock[port], flags); val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); @@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static void tegra_gpio_irq_shutdown(struct irq_data *d) +{ + int gpio = d->hwirq; + + gpio_unlock_as_irq(&tegra_gpio_chip, gpio); +} + static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct tegra_gpio_bank *bank; @@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, + .irq_shutdown = tegra_gpio_irq_shutdown, #ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_irq_set_wake, #endif @@ -413,6 +429,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) int i; int j; + dev = &pdev->dev; + match = of_match_device(tegra_gpio_of_match, &pdev->dev); if (!match) { dev_err(&pdev->dev, "Error: No device match found\n"); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index d8e4f6efcb2..0c7e891c865 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -594,7 +594,7 @@ static struct platform_driver gpio_twl4030_driver = { .driver = { .name = "twl4030_gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(twl_gpio_match), + .of_match_table = twl_gpio_match, }, .probe = gpio_twl4030_probe, .remove = gpio_twl4030_remove, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 5c1ef2b3ef1..ae0ffdce8bd 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -11,7 +11,7 @@ */ #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/export.h> #include <linux/acpi_gpio.h> #include <linux/acpi.h> @@ -33,14 +33,15 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) } /** - * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API + * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") * @pin: ACPI GPIO pin number (0-based, controller-relative) * - * Returns GPIO number to use with Linux generic GPIO API, or errno error value + * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR + * error value */ -int acpi_get_gpio(char *path, int pin) +static struct gpio_desc *acpi_get_gpiod(char *path, int pin) { struct gpio_chip *chip; acpi_handle handle; @@ -48,18 +49,17 @@ int acpi_get_gpio(char *path, int pin) status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) - return -ENODEV; + return ERR_PTR(-ENODEV); chip = gpiochip_find(handle, acpi_gpiochip_find); if (!chip) - return -ENODEV; + return ERR_PTR(-ENODEV); - if (!gpio_is_valid(chip->base + pin)) - return -EINVAL; + if (pin < 0 || pin > chip->ngpio) + return ERR_PTR(-EINVAL); - return chip->base + pin; + return gpio_to_desc(chip->base + pin); } -EXPORT_SYMBOL_GPL(acpi_get_gpio); static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { @@ -73,15 +73,8 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { struct acpi_gpio_evt_pin *evt_pin = data; - struct acpi_object_list args; - union acpi_object arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = evt_pin->pin; - args.count = 1; - args.pointer = &arg; - - acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL); + acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); return IRQ_HANDLED; } @@ -201,10 +194,48 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); +/** + * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * @chip: gpio chip + * + * Free interrupts associated with the _EVT method for the given GPIO chip. + * + * The remaining ACPI event interrupts associated with the chip are freed + * automatically. + */ +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +{ + acpi_handle handle; + acpi_status status; + struct list_head *evt_pins; + struct acpi_gpio_evt_pin *evt_pin, *ep; + + if (!chip->dev || !chip->to_irq) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); + if (ACPI_FAILURE(status)) + return; + + list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { + devm_free_irq(chip->dev, evt_pin->irq, evt_pin); + list_del(&evt_pin->node); + kfree(evt_pin); + } + + acpi_detach_data(handle, acpi_gpio_evt_dh); + kfree(evt_pins); +} +EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; - int gpio; + struct gpio_desc *desc; int n; }; @@ -215,37 +246,39 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) if (ares->type != ACPI_RESOURCE_TYPE_GPIO) return 1; - if (lookup->n++ == lookup->index && lookup->gpio < 0) { + if (lookup->n++ == lookup->index && !lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; - lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, - agpio->pin_table[0]); + lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, + agpio->pin_table[0]); lookup->info.gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + lookup->info.active_low = + agpio->polarity == ACPI_ACTIVE_LOW; } return 1; } /** - * acpi_get_gpio_by_index() - get a GPIO number from device resources + * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources * @dev: pointer to a device to get GPIO from * @index: index of GpioIo/GpioInt resource (starting from %0) * @info: info pointer to fill in (optional) * * Function goes through ACPI resources for @dev and based on @index looks - * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, + * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor, * and returns it. @index matches GpioIo/GpioInt resources only so if there * are total %3 GPIO resources, the index goes from %0 to %2. * - * If the GPIO cannot be translated or there is an error, negative errno is + * If the GPIO cannot be translated or there is an error an ERR_PTR is * returned. * * Note: if the GPIO resource has multiple entries in the pin list, this * function only returns the first. */ -int acpi_get_gpio_by_index(struct device *dev, int index, - struct acpi_gpio_info *info) +struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) { struct acpi_gpio_lookup lookup; struct list_head resource_list; @@ -254,65 +287,26 @@ int acpi_get_gpio_by_index(struct device *dev, int index, int ret; if (!dev) - return -EINVAL; + return ERR_PTR(-EINVAL); handle = ACPI_HANDLE(dev); if (!handle || acpi_bus_get_device(handle, &adev)) - return -ENODEV; + return ERR_PTR(-ENODEV); memset(&lookup, 0, sizeof(lookup)); lookup.index = index; - lookup.gpio = -ENODEV; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, &lookup); if (ret < 0) - return ret; + return ERR_PTR(ret); acpi_dev_free_resource_list(&resource_list); - if (lookup.gpio >= 0 && info) + if (lookup.desc && info) *info = lookup.info; - return lookup.gpio; + return lookup.desc ? lookup.desc : ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); - -/** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip - * - * Free interrupts associated with the _EVT method for the given GPIO chip. - * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. - */ -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) -{ - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; - struct acpi_gpio_evt_pin *evt_pin, *ep; - - if (!chip->dev || !chip->to_irq) - return; - - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; - - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) - return; - - list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { - devm_free_irq(chip->dev, evt_pin->irq, evt_pin); - list_del(&evt_pin->node); - kfree(evt_pin); - } - - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); -} -EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); +EXPORT_SYMBOL_GPL(acpi_get_gpiod_by_index); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 0dfaf20e4da..e0a98f581f5 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -15,19 +15,21 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> +struct gpio_desc; + /* Private data structure for of_gpiochip_find_and_xlate */ struct gg_data { enum of_gpio_flags *flags; struct of_phandle_args gpiospec; - int out_gpio; + struct gpio_desc *out_gpio; }; /* Private function for resolving node pointer to gpio_chip */ @@ -45,28 +47,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) if (ret < 0) return false; - gg_data->out_gpio = ret + gc->base; + gg_data->out_gpio = gpio_to_desc(ret + gc->base); return true; } /** - * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API * @np: device node to get GPIO from * @propname: property name containing gpio specifier(s) * @index: index of the GPIO * @flags: a flags pointer to fill in * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno * value on the error condition. If @flags is not NULL the function also fills * in flags for the GPIO. */ -int of_get_named_gpio_flags(struct device_node *np, const char *propname, - int index, enum of_gpio_flags *flags) +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *propname, int index, enum of_gpio_flags *flags) { /* Return -EPROBE_DEFER to support probe() functions to be called * later when the GPIO actually becomes available */ - struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; + struct gg_data gg_data = { + .flags = flags, + .out_gpio = ERR_PTR(-EPROBE_DEFER) + }; int ret; /* .of_xlate might decide to not fill in the flags, so clear it. */ @@ -78,16 +83,17 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, if (ret) { pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", __func__, np->full_name, index); - return ret; + return ERR_PTR(ret); } gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); of_node_put(gg_data.gpiospec.np); - pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); + pr_debug("%s exited with status %d\n", __func__, + PTR_RET(gg_data.out_gpio)); return gg_data.out_gpio; } -EXPORT_SYMBOL(of_get_named_gpio_flags); +EXPORT_SYMBOL(of_get_named_gpiod_flags); /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags @@ -190,10 +196,15 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) struct of_phandle_args pinspec; struct pinctrl_dev *pctldev; int index = 0, ret; + const char *name; + static const char group_names_propname[] = "gpio-ranges-group-names"; + struct property *group_names; if (!np) return; + group_names = of_find_property(np, group_names_propname, NULL); + for (;; index++) { ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, index, &pinspec); @@ -204,14 +215,56 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (!pctldev) break; - ret = gpiochip_add_pin_range(chip, - pinctrl_dev_get_devname(pctldev), - pinspec.args[0], - pinspec.args[1], - pinspec.args[2]); - - if (ret) - break; + if (pinspec.args[2]) { + if (group_names) { + ret = of_property_read_string_index(np, + group_names_propname, + index, &name); + if (strlen(name)) { + pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n", + np->full_name); + break; + } + } + /* npins != 0: linear range */ + ret = gpiochip_add_pin_range(chip, + pinctrl_dev_get_devname(pctldev), + pinspec.args[0], + pinspec.args[1], + pinspec.args[2]); + if (ret) + break; + } else { + /* npins == 0: special range */ + if (pinspec.args[1]) { + pr_err("%s: Illegal gpio-range format.\n", + np->full_name); + break; + } + + if (!group_names) { + pr_err("%s: GPIO group range requested but no %s property.\n", + np->full_name, group_names_propname); + break; + } + + ret = of_property_read_string_index(np, + group_names_propname, + index, &name); + if (ret) + break; + + if (!strlen(name)) { + pr_err("%s: Group name of GPIO group range cannot be the empty string.\n", + np->full_name); + break; + } + + ret = gpiochip_add_pingroup_range(chip, pctldev, + pinspec.args[0], name); + if (ret) + break; + } } } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index dadbac27726..7dd44615029 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -10,22 +10,18 @@ #include <linux/seq_file.h> #include <linux/gpio.h> #include <linux/of_gpio.h> +#include <linux/acpi_gpio.h> #include <linux/idr.h> #include <linux/slab.h> #define CREATE_TRACE_POINTS #include <trace/events/gpio.h> -/* Optional implementation infrastructure for GPIO interfaces. +/* Implementation infrastructure for GPIO interfaces. * - * Platforms may want to use this if they tend to use very many GPIOs - * that aren't part of a System-On-Chip core; or across I2C/SPI/etc. - * - * When kernel footprint or instruction count is an issue, simpler - * implementations may be preferred. The GPIO programming interface - * allows for inlining speed-critical get/set operations for common - * cases, so that access to SOC-integrated GPIOs can sometimes cost - * only an instruction or two per bit. + * The GPIO programming interface allows for inlining speed-critical + * get/set operations for common cases, so that access to SOC-integrated + * GPIOs can sometimes cost only an instruction or two per bit. */ @@ -57,9 +53,10 @@ struct gpio_desc { #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ #define FLAG_TRIG_FALL 4 /* trigger on falling edge */ #define FLAG_TRIG_RISE 5 /* trigger on rising edge */ -#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ +#define FLAG_ACTIVE_LOW 6 /* value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -74,34 +71,50 @@ static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) +static DEFINE_MUTEX(gpio_lookup_lock); +static LIST_HEAD(gpio_lookup_list); static LIST_HEAD(gpio_chips); #ifdef CONFIG_GPIO_SYSFS static DEFINE_IDR(dirent_idr); #endif -/* - * Internal gpiod_* API using descriptors instead of the integer namespace. - * Most of this should eventually go public. - */ static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); -static int gpiod_direction_input(struct gpio_desc *desc); -static int gpiod_direction_output(struct gpio_desc *desc, int value); -static int gpiod_get_direction(const struct gpio_desc *desc); -static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); -static int gpiod_get_value_cansleep(const struct gpio_desc *desc); -static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); -static int gpiod_get_value(const struct gpio_desc *desc); -static void gpiod_set_value(struct gpio_desc *desc, int value); -static int gpiod_cansleep(const struct gpio_desc *desc); -static int gpiod_to_irq(const struct gpio_desc *desc); -static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); -static int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc); -static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); -static void gpiod_unexport(struct gpio_desc *desc); +#ifdef CONFIG_DEBUG_FS +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#else +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#endif static inline void desc_set_label(struct gpio_desc *d, const char *label) { @@ -121,23 +134,36 @@ static int gpio_chip_hwgpio(const struct gpio_desc *desc) /** * Convert a GPIO number to its descriptor */ -static struct gpio_desc *gpio_to_desc(unsigned gpio) +struct gpio_desc *gpio_to_desc(unsigned gpio) { if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) return NULL; else return &gpio_desc[gpio]; } +EXPORT_SYMBOL_GPL(gpio_to_desc); + +/** + * Convert an offset on a certain chip to a corresponding descriptor + */ +static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, + unsigned int offset) +{ + unsigned int gpio = chip->base + offset; + + return gpio_to_desc(gpio); +} /** * Convert a GPIO descriptor to the integer namespace. * This should disappear in the future but is needed since we still * use GPIO numbers for error messages and sysfs nodes */ -static int desc_to_gpio(const struct gpio_desc *desc) +int desc_to_gpio(const struct gpio_desc *desc) { return desc - &gpio_desc[0]; } +EXPORT_SYMBOL_GPL(desc_to_gpio); /* Warn when drivers omit gpio_request() calls -- legal but ill-advised @@ -172,16 +198,15 @@ static int gpio_ensure_requested(struct gpio_desc *desc) return 0; } -static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) +/** + * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs + * @desc: descriptor to return the chip of + */ +struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) { return desc ? desc->chip : NULL; } - -/* caller holds gpio_lock *OR* gpio is marked as requested */ -struct gpio_chip *gpio_to_chip(unsigned gpio) -{ - return gpiod_to_chip(gpio_to_desc(gpio)); -} +EXPORT_SYMBOL_GPL(gpiod_to_chip); /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) @@ -207,8 +232,15 @@ static int gpiochip_find_base(int ngpio) } } -/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ -static int gpiod_get_direction(const struct gpio_desc *desc) +/** + * gpiod_get_direction - return the current direction of a GPIO + * @desc: GPIO to get the direction of + * + * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error. + * + * This function may sleep if gpiod_cansleep() is true. + */ +int gpiod_get_direction(const struct gpio_desc *desc) { struct gpio_chip *chip; unsigned offset; @@ -234,6 +266,7 @@ static int gpiod_get_direction(const struct gpio_desc *desc) } return status; } +EXPORT_SYMBOL_GPL(gpiod_get_direction); #ifdef CONFIG_GPIO_SYSFS @@ -318,17 +351,10 @@ static ssize_t gpio_value_show(struct device *dev, mutex_lock(&sysfs_lock); - if (!test_bit(FLAG_EXPORT, &desc->flags)) { + if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; - } else { - int value; - - value = !!gpiod_get_value_cansleep(desc); - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - value = !value; - - status = sprintf(buf, "%d\n", value); - } + else + status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); mutex_unlock(&sysfs_lock); return status; @@ -351,9 +377,7 @@ static ssize_t gpio_value_store(struct device *dev, status = kstrtol(buf, 0, &value); if (status == 0) { - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - value = !value; - gpiod_set_value_cansleep(desc, value != 0); + gpiod_set_value_cansleep(desc, value); status = size; } } @@ -395,6 +419,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { + gpiod_unlock_as_irq(desc); ret = 0; goto free_id; } @@ -433,6 +458,12 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (ret < 0) goto free_id; + ret = gpiod_lock_as_irq(desc); + if (ret < 0) { + gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); + goto free_id; + } + desc->flags |= gpio_flags; return 0; @@ -736,7 +767,7 @@ static struct class gpio_class = { /** - * gpio_export - export a GPIO through sysfs + * gpiod_export - export a GPIO through sysfs * @gpio: gpio to make available, already requested * @direction_may_change: true if userspace may change gpio direction * Context: arch_initcall or later @@ -750,7 +781,7 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ -static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) +int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { unsigned long flags; int status; @@ -828,12 +859,7 @@ fail_unlock: status); return status; } - -int gpio_export(unsigned gpio, bool direction_may_change) -{ - return gpiod_export(gpio_to_desc(gpio), direction_may_change); -} -EXPORT_SYMBOL_GPL(gpio_export); +EXPORT_SYMBOL_GPL(gpiod_export); static int match_export(struct device *dev, const void *data) { @@ -841,7 +867,7 @@ static int match_export(struct device *dev, const void *data) } /** - * gpio_export_link - create a sysfs link to an exported GPIO node + * gpiod_export_link - create a sysfs link to an exported GPIO node * @dev: device under which to create symlink * @name: name of the symlink * @gpio: gpio to create symlink to, already exported @@ -851,8 +877,8 @@ static int match_export(struct device *dev, const void *data) * * Returns zero on success, else an error. */ -static int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc) +int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc) { int status = -EINVAL; @@ -883,15 +909,10 @@ static int gpiod_export_link(struct device *dev, const char *name, return status; } - -int gpio_export_link(struct device *dev, const char *name, unsigned gpio) -{ - return gpiod_export_link(dev, name, gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_export_link); +EXPORT_SYMBOL_GPL(gpiod_export_link); /** - * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value + * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value * @gpio: gpio to change * @value: non-zero to use active low, i.e. inverted values * @@ -902,7 +923,7 @@ EXPORT_SYMBOL_GPL(gpio_export_link); * * Returns zero on success, else an error. */ -static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) { struct device *dev = NULL; int status = -EINVAL; @@ -933,20 +954,15 @@ unlock: return status; } - -int gpio_sysfs_set_active_low(unsigned gpio, int value) -{ - return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); -} -EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); +EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); /** - * gpio_unexport - reverse effect of gpio_export() + * gpiod_unexport - reverse effect of gpio_export() * @gpio: gpio to make unavailable * * This is implicit on gpio_free(). */ -static void gpiod_unexport(struct gpio_desc *desc) +void gpiod_unexport(struct gpio_desc *desc) { int status = 0; struct device *dev = NULL; @@ -979,12 +995,7 @@ static void gpiod_unexport(struct gpio_desc *desc) pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), status); } - -void gpio_unexport(unsigned gpio) -{ - gpiod_unexport(gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_unexport); +EXPORT_SYMBOL_GPL(gpiod_unexport); static int gpiochip_export(struct gpio_chip *chip) { @@ -1091,27 +1102,6 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) { } -static inline int gpiod_export(struct gpio_desc *desc, - bool direction_may_change) -{ - return -ENOSYS; -} - -static inline int gpiod_export_link(struct device *dev, const char *name, - struct gpio_desc *desc) -{ - return -ENOSYS; -} - -static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) -{ - return -ENOSYS; -} - -static inline void gpiod_unexport(struct gpio_desc *desc) -{ -} - #endif /* CONFIG_GPIO_SYSFS */ /* @@ -1320,6 +1310,53 @@ EXPORT_SYMBOL_GPL(gpiochip_find); #ifdef CONFIG_PINCTRL /** + * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping + * @chip: the gpiochip to add the range for + * @pinctrl: the dev_name() of the pin controller to map to + * @gpio_offset: the start offset in the current gpio_chip number space + * @pin_group: name of the pin group inside the pin controller + */ +int gpiochip_add_pingroup_range(struct gpio_chip *chip, + struct pinctrl_dev *pctldev, + unsigned int gpio_offset, const char *pin_group) +{ + struct gpio_pin_range *pin_range; + int ret; + + pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + return -ENOMEM; + } + + /* Use local offset as range ID */ + pin_range->range.id = gpio_offset; + pin_range->range.gc = chip; + pin_range->range.name = chip->label; + pin_range->range.base = chip->base + gpio_offset; + pin_range->pctldev = pctldev; + + ret = pinctrl_get_group_pins(pctldev, pin_group, + &pin_range->range.pins, + &pin_range->range.npins); + if (ret < 0) + return ret; + + pinctrl_add_gpio_range(pctldev, &pin_range->range); + + pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PINGRP %s\n", + chip->label, gpio_offset, + gpio_offset + pin_range->range.npins - 1, + pinctrl_dev_get_devname(pctldev), pin_group); + + list_add_tail(&pin_range->node, &chip->pin_ranges); + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); + +/** * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping * @chip: the gpiochip to add the range for * @pinctrl_name: the dev_name() of the pin controller to map to @@ -1623,7 +1660,16 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * rely on gpio_request() having been called beforehand. */ -static int gpiod_direction_input(struct gpio_desc *desc) +/** + * gpiod_direction_input - set the GPIO direction to input + * @desc: GPIO to set to input + * + * Set the direction of the passed GPIO to input, such as gpiod_get_value() can + * be called safely on it. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_input(struct gpio_desc *desc) { unsigned long flags; struct gpio_chip *chip; @@ -1637,8 +1683,9 @@ static int gpiod_direction_input(struct gpio_desc *desc) chip = desc->chip; if (!chip->get || !chip->direction_input) { - pr_warn("%s: missing get() or direction_input() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing get() or direction_input() operations\n", + __func__); return -EIO; } @@ -1658,8 +1705,7 @@ static int gpiod_direction_input(struct gpio_desc *desc) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1677,18 +1723,22 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s status %d\n", __func__, status); return status; } +EXPORT_SYMBOL_GPL(gpiod_direction_input); -int gpio_direction_input(unsigned gpio) -{ - return gpiod_direction_input(gpio_to_desc(gpio)); -} -EXPORT_SYMBOL_GPL(gpio_direction_input); - -static int gpiod_direction_output(struct gpio_desc *desc, int value) +/** + * gpiod_direction_output - set the GPIO direction to input + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; @@ -1700,6 +1750,14 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) return -EINVAL; } + /* GPIOs used for IRQs shall not be set as output */ + if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { + gpiod_err(desc, + "%s: tried to set a GPIO tied to an IRQ as output\n", + __func__); + return -EIO; + } + /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) return gpiod_direction_input(desc); @@ -1710,8 +1768,9 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) chip = desc->chip; if (!chip->set || !chip->direction_output) { - pr_warn("%s: missing set() or direction_output() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing set() or direction_output() operations\n", + __func__); return -EIO; } @@ -1731,8 +1790,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1750,26 +1808,20 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } - -int gpio_direction_output(unsigned gpio, int value) -{ - return gpiod_direction_output(gpio_to_desc(gpio), value); -} -EXPORT_SYMBOL_GPL(gpio_direction_output); +EXPORT_SYMBOL_GPL(gpiod_direction_output); /** - * gpio_set_debounce - sets @debounce time for a @gpio + * gpiod_set_debounce - sets @debounce time for a @gpio * @gpio: the gpio to set debounce time * @debounce: debounce time is microseconds * * returns -ENOTSUPP if the controller does not support setting * debounce. */ -static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) +int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) { unsigned long flags; struct gpio_chip *chip; @@ -1783,8 +1835,9 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) chip = desc->chip; if (!chip->set || !chip->set_debounce) { - pr_debug("%s: missing set() or set_debounce() operations\n", - __func__); + gpiod_dbg(desc, + "%s: missing set() or set_debounce() operations\n", + __func__); return -ENOTSUPP; } @@ -1806,17 +1859,23 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } +EXPORT_SYMBOL_GPL(gpiod_set_debounce); -int gpio_set_debounce(unsigned gpio, unsigned debounce) +/** + * gpiod_is_active_low - test whether a GPIO is active-low or not + * @desc: the gpio descriptor to test + * + * Returns 1 if the GPIO is active-low, 0 otherwise. + */ +int gpiod_is_active_low(const struct gpio_desc *desc) { - return gpiod_set_debounce(gpio_to_desc(gpio), debounce); + return test_bit(FLAG_ACTIVE_LOW, &desc->flags); } -EXPORT_SYMBOL_GPL(gpio_set_debounce); +EXPORT_SYMBOL_GPL(gpiod_is_active_low); /* I/O calls are only valid after configuration completed; the relevant * "is this a valid GPIO" error checks should already have been done. @@ -1840,42 +1899,68 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * that the GPIO was actually requested. */ -/** - * __gpio_get_value() - return a gpio's value - * @gpio: gpio whose value will be returned - * Context: any - * - * This is used directly or indirectly to implement gpio_get_value(). - * It returns the zero or nonzero value provided by the associated - * gpio_chip.get() method; or zero if no such method is provided. - */ -static int gpiod_get_value(const struct gpio_desc *desc) +static int _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; int value; int offset; - if (!desc) - return 0; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - /* Should be using gpio_get_value_cansleep() */ - WARN_ON(chip->can_sleep); value = chip->get ? chip->get(chip, offset) : 0; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } -int __gpio_get_value(unsigned gpio) +/** + * gpiod_get_raw_value() - return a gpio's raw value + * @desc: gpio whose value will be returned + * + * Return the GPIO's raw value, i.e. the value of the physical line disregarding + * its ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +int gpiod_get_raw_value(const struct gpio_desc *desc) +{ + if (!desc) + return 0; + /* Should be using gpio_get_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + return _gpiod_get_raw_value(desc); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_value); + +/** + * gpiod_get_value() - return a gpio's value + * @desc: gpio whose value will be returned + * + * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into + * account. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +int gpiod_get_value(const struct gpio_desc *desc) { - return gpiod_get_value(gpio_to_desc(gpio)); + int value; + if (!desc) + return 0; + /* Should be using gpio_get_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + + value = _gpiod_get_raw_value(desc); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + + return value; } -EXPORT_SYMBOL_GPL(__gpio_get_value); +EXPORT_SYMBOL_GPL(gpiod_get_value); /* * _gpio_set_open_drain_value() - Set the open drain gpio's value. - * @gpio: Gpio whose state need to be set. - * @chip: Gpio chip. + * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) @@ -1895,14 +1980,14 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), value, err); if (err < 0) - pr_err("%s: Error in set_value for open drain gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open drain err %d\n", + __func__, err); } /* - * _gpio_set_open_source() - Set the open source gpio's value. - * @gpio: Gpio whose state need to be set. - * @chip: Gpio chip. + * _gpio_set_open_source_value() - Set the open source gpio's value. + * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) @@ -1922,28 +2007,16 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), !value, err); if (err < 0) - pr_err("%s: Error in set_value for open source gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open source err %d\n", + __func__, err); } -/** - * __gpio_set_value() - assign a gpio's value - * @gpio: gpio whose value will be assigned - * @value: value to assign - * Context: any - * - * This is used directly or indirectly to implement gpio_set_value(). - * It invokes the associated gpio_chip.set() method. - */ -static void gpiod_set_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) { struct gpio_chip *chip; - if (!desc) - return; chip = desc->chip; - /* Should be using gpio_set_value_cansleep() */ - WARN_ON(chip->can_sleep); trace_gpio_value(desc_to_gpio(desc), 0, value); if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) _gpio_set_open_drain_value(desc, value); @@ -1953,44 +2026,71 @@ static void gpiod_set_value(struct gpio_desc *desc, int value) chip->set(chip, gpio_chip_hwgpio(desc), value); } -void __gpio_set_value(unsigned gpio, int value) +/** + * gpiod_set_raw_value() - assign a gpio's raw value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the raw value of the GPIO, i.e. the value of its physical line without + * regard for its ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +void gpiod_set_raw_value(struct gpio_desc *desc, int value) { - return gpiod_set_value(gpio_to_desc(gpio), value); + if (!desc) + return; + /* Should be using gpio_set_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + _gpiod_set_raw_value(desc, value); } -EXPORT_SYMBOL_GPL(__gpio_set_value); +EXPORT_SYMBOL_GPL(gpiod_set_raw_value); /** - * __gpio_cansleep() - report whether gpio value access will sleep - * @gpio: gpio in question - * Context: any + * gpiod_set_value() - assign a gpio's value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account * - * This is used directly or indirectly to implement gpio_cansleep(). It - * returns nonzero if access reading or writing the GPIO value can sleep. + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. */ -static int gpiod_cansleep(const struct gpio_desc *desc) +void gpiod_set_value(struct gpio_desc *desc, int value) { if (!desc) - return 0; - /* only call this on GPIOs that are valid! */ - return desc->chip->can_sleep; + return; + /* Should be using gpio_set_value_cansleep() */ + WARN_ON(desc->chip->can_sleep); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + _gpiod_set_raw_value(desc, value); } +EXPORT_SYMBOL_GPL(gpiod_set_value); -int __gpio_cansleep(unsigned gpio) +/** + * gpiod_cansleep() - report whether gpio value access may sleep + * @desc: gpio to check + * + */ +int gpiod_cansleep(const struct gpio_desc *desc) { - return gpiod_cansleep(gpio_to_desc(gpio)); + if (!desc) + return 0; + return desc->chip->can_sleep; } -EXPORT_SYMBOL_GPL(__gpio_cansleep); +EXPORT_SYMBOL_GPL(gpiod_cansleep); /** - * __gpio_to_irq() - return the IRQ corresponding to a GPIO - * @gpio: gpio whose IRQ will be returned (already requested) - * Context: any + * gpiod_to_irq() - return the IRQ corresponding to a GPIO + * @desc: gpio whose IRQ will be returned (already requested) * - * This is used directly or indirectly to implement gpio_to_irq(). - * It returns the number of the IRQ signaled by this (input) GPIO, - * or a negative errno. + * Return the IRQ corresponding to the passed GPIO, or an error code in case of + * error. */ -static int gpiod_to_irq(const struct gpio_desc *desc) +int gpiod_to_irq(const struct gpio_desc *desc) { struct gpio_chip *chip; int offset; @@ -2001,62 +2101,366 @@ static int gpiod_to_irq(const struct gpio_desc *desc) offset = gpio_chip_hwgpio(desc); return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; } +EXPORT_SYMBOL_GPL(gpiod_to_irq); -int __gpio_to_irq(unsigned gpio) +/** + * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ + * @gpio: the GPIO line to lock as used for IRQ + * + * This is used directly by GPIO drivers that want to lock down + * a certain GPIO line to be used as IRQs, for example in the + * .to_irq() callback of their gpio_chip, or in the .irq_enable() + * of its irq_chip implementation if the GPIO is known from that + * code. + */ +int gpiod_lock_as_irq(struct gpio_desc *desc) { - return gpiod_to_irq(gpio_to_desc(gpio)); + if (!desc) + return -EINVAL; + + if (test_bit(FLAG_IS_OUT, &desc->flags)) { + gpiod_err(desc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); + return -EIO; + } + + set_bit(FLAG_USED_AS_IRQ, &desc->flags); + return 0; } -EXPORT_SYMBOL_GPL(__gpio_to_irq); +EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_lock_as_irq); -/* There's no value in making it easy to inline GPIO calls that may sleep. - * Common examples include ones connected to I2C or SPI chips. +/** + * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ + * @gpio: the GPIO line to unlock from IRQ usage + * + * This is used directly by GPIO drivers that want to indicate + * that a certain GPIO is no longer used exclusively for IRQ. */ +void gpiod_unlock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return; -static int gpiod_get_value_cansleep(const struct gpio_desc *desc) + clear_bit(FLAG_USED_AS_IRQ, &desc->flags); +} +EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); + +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); + +/** + * gpiod_get_raw_value_cansleep() - return a gpio's raw value + * @desc: gpio whose value will be returned + * + * Return the GPIO's raw value, i.e. the value of the physical line disregarding + * its ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) +{ + might_sleep_if(extra_checks); + if (!desc) + return 0; + return _gpiod_get_raw_value(desc); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep); + +/** + * gpiod_get_value_cansleep() - return a gpio's value + * @desc: gpio whose value will be returned + * + * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into + * account. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_get_value_cansleep(const struct gpio_desc *desc) { - struct gpio_chip *chip; int value; - int offset; might_sleep_if(extra_checks); if (!desc) return 0; - chip = desc->chip; - offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; - trace_gpio_value(desc_to_gpio(desc), 1, value); + + value = _gpiod_get_raw_value(desc); + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return value; } +EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); -int gpio_get_value_cansleep(unsigned gpio) +/** + * gpiod_set_raw_value_cansleep() - assign a gpio's raw value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the raw value of the GPIO, i.e. the value of its physical line without + * regard for its ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) { - return gpiod_get_value_cansleep(gpio_to_desc(gpio)); + might_sleep_if(extra_checks); + if (!desc) + return; + _gpiod_set_raw_value(desc, value); } -EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); +EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); -static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +/** + * gpiod_set_value_cansleep() - assign a gpio's value + * @desc: gpio whose value will be assigned + * @value: value to assign + * + * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { - struct gpio_chip *chip; - might_sleep_if(extra_checks); if (!desc) return; - chip = desc->chip; - trace_gpio_value(desc_to_gpio(desc), 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - _gpio_set_open_drain_value(desc, value); - else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - _gpio_set_open_source_value(desc, value); + + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + _gpiod_set_raw_value(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); + +/** + * gpiod_add_table() - register GPIO device consumers + * @table: array of consumers to register + * @num: number of consumers in table + */ +void gpiod_add_table(struct gpiod_lookup *table, size_t size) +{ + mutex_lock(&gpio_lookup_lock); + + while (size--) { + list_add_tail(&table->list, &gpio_lookup_list); + table++; + } + + mutex_unlock(&gpio_lookup_lock); +} + +/* + * Caller must have a acquired gpio_lookup_lock + */ +static struct gpio_chip *find_chip_by_name(const char *name) +{ + struct gpio_chip *chip = NULL; + + list_for_each_entry(chip, &gpio_lookup_list, list) { + if (chip->label == NULL) + continue; + if (!strcmp(chip->label, name)) + break; + } + + return chip; +} + +#ifdef CONFIG_OF +static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + char prop_name[32]; /* 32 is max size of property name */ + enum of_gpio_flags of_flags; + struct gpio_desc *desc; + + if (con_id) + snprintf(prop_name, 32, "%s-gpios", con_id); else - chip->set(chip, gpio_chip_hwgpio(desc), value); + snprintf(prop_name, 32, "gpios"); + + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + + if (IS_ERR(desc)) + return desc; + + if (of_flags & OF_GPIO_ACTIVE_LOW) + *flags |= GPIOF_ACTIVE_LOW; + + return desc; +} +#else +static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + return ERR_PTR(-ENODEV); +} +#endif + +static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) +{ + struct acpi_gpio_info info; + struct gpio_desc *desc; + + desc = acpi_get_gpiod_by_index(dev, idx, &info); + if (IS_ERR(desc)) + return desc; + + if (info.gpioint && info.active_low) + *flags |= GPIOF_ACTIVE_LOW; + + return desc; } -void gpio_set_value_cansleep(unsigned gpio, int value) +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, unsigned long *flags) { - return gpiod_set_value_cansleep(gpio_to_desc(gpio), value); + const char *dev_id = dev ? dev_name(dev) : NULL; + struct gpio_desc *desc = ERR_PTR(-ENODEV); + unsigned int match, best = 0; + struct gpiod_lookup *p; + + mutex_lock(&gpio_lookup_lock); + + list_for_each_entry(p, &gpio_lookup_list, list) { + match = 0; + + if (p->dev_id) { + if (!dev_id || strcmp(p->dev_id, dev_id)) + continue; + + match += 2; + } + + if (p->con_id) { + if (!con_id || strcmp(p->con_id, con_id)) + continue; + + match += 1; + } + + if (p->idx != idx) + continue; + + if (match > best) { + struct gpio_chip *chip; + + chip = find_chip_by_name(p->chip_label); + + if (!chip) { + dev_warn(dev, "cannot find GPIO chip %s\n", + p->chip_label); + continue; + } + + if (chip->ngpio >= p->chip_hwnum) { + dev_warn(dev, "GPIO chip %s has %d GPIOs\n", + chip->label, chip->ngpio); + continue; + } + + desc = gpio_to_desc(chip->base + p->chip_hwnum); + *flags = p->flags; + + if (match != 3) + best = match; + else + break; + } + } + + mutex_unlock(&gpio_lookup_lock); + + return desc; +} + +/** + * gpio_get - obtain a GPIO for a given GPIO function + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Return the GPIO descriptor corresponding to the function con_id of device + * dev, or an IS_ERR() condition if an error occured. + */ +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) +{ + return gpiod_get_index(dev, con_id, 0); +} +EXPORT_SYMBOL_GPL(gpiod_get); + +/** + * gpiod_get_index - obtain a GPIO from a multi-index GPIO function + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @idx: index of the GPIO to obtain in the consumer + * + * This variant of gpiod_get() allows to access GPIOs other than the first + * defined one for functions that define several GPIOs. + * + * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + */ +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx) +{ + struct gpio_desc *desc; + int status; + unsigned long flags = 0; + + dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); + + /* Using device tree? */ + if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) { + dev_dbg(dev, "using device tree for GPIO lookup\n"); + desc = of_find_gpio(dev, con_id, idx, &flags); + } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) { + dev_dbg(dev, "using ACPI for GPIO lookup\n"); + desc = acpi_find_gpio(dev, con_id, idx, &flags); + } else { + dev_dbg(dev, "using lookup tables for GPIO lookup"); + desc = gpiod_find(dev, con_id, idx, &flags); + } + + if (IS_ERR(desc)) { + dev_warn(dev, "lookup for GPIO %s failed\n", con_id); + return desc; + } + + status = gpiod_request(desc, con_id); + + if (status < 0) + return ERR_PTR(status); + + if (flags & GPIOF_ACTIVE_LOW) + set_bit(FLAG_ACTIVE_LOW, &desc->flags); + + return desc; +} +EXPORT_SYMBOL_GPL(gpiod_get_index); + +/** + * gpiod_put - dispose of a GPIO descriptor + * @desc: GPIO descriptor to dispose of + * + * No descriptor can be used after gpiod_put() has been called on it. + */ +void gpiod_put(struct gpio_desc *desc) +{ + gpiod_free(desc); } -EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); +EXPORT_SYMBOL_GPL(gpiod_put); #ifdef CONFIG_DEBUG_FS @@ -2066,6 +2470,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; struct gpio_desc *gdesc = &chip->desc[0]; int is_out; + int is_irq; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) @@ -2073,12 +2478,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", + is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", gpio, gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") - : "? "); + : "? ", + is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } } diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.h b/drivers/gpu/drm/gma500/mdfld_dsi_output.h index 45d5af0546b..5b646c1f0c3 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.h +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.h @@ -39,7 +39,7 @@ #include "psb_intel_reg.h" #include "mdfld_output.h" -#include <asm/mrst.h> +#include <asm/intel-mid.h> #define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) #define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end)) diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c index 08747fd7105..7a9ce000fd8 100644 --- a/drivers/gpu/drm/gma500/oaktrail_device.c +++ b/drivers/gpu/drm/gma500/oaktrail_device.c @@ -26,7 +26,7 @@ #include "psb_drv.h" #include "psb_reg.h" #include "psb_intel_reg.h" -#include <asm/mrst.h> +#include <asm/intel-mid.h> #include <asm/intel_scu_ipc.h> #include "mid_bios.h" #include "intel_bios.h" diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index e77d7214fca..3ece553311f 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -22,7 +22,7 @@ #include <linux/i2c.h> #include <drm/drmP.h> -#include <asm/mrst.h> +#include <asm/intel-mid.h> #include "intel_bios.h" #include "psb_drv.h" diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 2ebd6ce4610..9c8a6bab822 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -164,7 +164,7 @@ static const u8 abituguru_bank2_max_threshold = 50; static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 }; /* * Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a - * special case the minium allowed pwm% setting for this is 30% (77) on + * special case the minimum allowed pwm% setting for this is 30% (77) on * some MB's this special case is handled in the code! */ static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 }; @@ -517,7 +517,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr); /* - * Volt sensor test, enable volt low alarm, set min value ridicously + * Volt sensor test, enable volt low alarm, set min value ridiculously * high, or vica versa if the reading is very high. If its a volt * sensor this should always give us an alarm. */ @@ -564,7 +564,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data, /* * Temp sensor test, enable sensor as a temp sensor, set beep value - * ridicously low (but not too low, otherwise uguru ignores it). + * ridiculously low (but not too low, otherwise uguru ignores it). * If its a temp sensor this should always give us an alarm. */ buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE; diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 0cac8c0b001..4ae74aa8cdc 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -176,7 +176,7 @@ struct abituguru3_data { /* * The abituguru3 supports up to 48 sensors, and thus has registers - * sets for 48 sensors, for convienence reasons / simplicity of the + * sets for 48 sensors, for convenience reasons / simplicity of the * code we always read and store all registers for all 48 sensors */ diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index a9e3d0152c0..8d40da314a8 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -381,8 +381,10 @@ static ssize_t show_str(struct device *dev, val = resource->oem_info; break; default: - BUG(); + WARN(1, "Implementation error: unexpected attribute index %d\n", + attr->index); val = ""; + break; } return sprintf(buf, "%s\n", val); @@ -436,7 +438,9 @@ static ssize_t show_val(struct device *dev, val = resource->trip[attr->index - 7] * 1000; break; default: - BUG(); + WARN(1, "Implementation error: unexpected attribute index %d\n", + attr->index); + break; } return sprintf(buf, "%llu\n", val); @@ -855,7 +859,8 @@ static void acpi_power_meter_notify(struct acpi_device *device, u32 event) dev_info(&device->dev, "Capping in progress.\n"); break; default: - BUG(); + WARN(1, "Unexpected event %d\n", event); + break; } mutex_unlock(&resource->lock); @@ -991,7 +996,7 @@ static int __init acpi_power_meter_init(void) result = acpi_bus_register_driver(&acpi_power_meter_driver); if (result < 0) - return -ENODEV; + return result; return 0; } diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index 751b1f0264a..04c08c2f79b 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -203,7 +203,6 @@ out_err: for (i--; i >= 0; i--) device_remove_file(&spi->dev, &ad_input[i].dev_attr); - spi_set_drvdata(spi, NULL); mutex_unlock(&adc->lock); return status; } @@ -218,7 +217,6 @@ static int adcxx_remove(struct spi_device *spi) for (i = 0; i < 3 + adc->channels; i++) device_remove_file(&spi->dev, &ad_input[i].dev_attr); - spi_set_drvdata(spi, NULL); mutex_unlock(&adc->lock); return 0; diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 3a6d9ef1c16..b3498acb9ab 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -616,7 +616,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) data->gpio = gpio; data->last_reading = jiffies; - }; /* last_reading */ + } /* last_reading */ if (!data->valid || time_after(jiffies, data->last_config + ADM1026_CONFIG_INTERVAL)) { @@ -700,7 +700,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev) } data->last_config = jiffies; - }; /* last_config */ + } /* last_config */ data->valid = 1; mutex_unlock(&data->update_lock); @@ -1791,7 +1791,7 @@ static int adm1026_detect(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { /* We need to be able to do byte I/O */ return -ENODEV; - }; + } /* Now, we do the remaining detection. */ diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c index da5f0789fb9..5994cf68e0a 100644 --- a/drivers/hwmon/adt7310.c +++ b/drivers/hwmon/adt7310.c @@ -42,13 +42,8 @@ static const u8 adt7310_reg_table[] = { static int adt7310_spi_read_word(struct device *dev, u8 reg) { struct spi_device *spi = to_spi_device(dev); - int ret; - ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ); - if (ret < 0) - return ret; - - return be16_to_cpu((__force __be16)ret); + return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ); } static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data) diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index addb5a4d506..562cc3881d3 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -700,7 +700,7 @@ static int find_trange_value(int trange) if (trange_values[i] == trange) return i; - return -ENODEV; + return -EINVAL; } static struct adt7462_data *adt7462_update_device(struct device *dev) @@ -1294,9 +1294,8 @@ static ssize_t set_pwm_tmax(struct device *dev, /* trange = tmax - tmin */ tmin = (data->pwm_tmin[attr->index] - 64) * 1000; trange_value = find_trange_value(trange - tmin); - if (trange_value < 0) - return -EINVAL; + return trange_value; temp = trange_value << ADT7462_PWM_RANGE_SHIFT; temp |= data->pwm_trange[attr->index] & ADT7462_PWM_HYST_MASK; diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 3ad9d849add..8d9f2a0e8ef 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -138,7 +138,7 @@ static inline u8 read_byte(struct i2c_client *client, u8 reg) dev_err(&client->dev, "Unable to read from register 0x%02x.\n", reg); return 0; - }; + } return res & 0xff; } @@ -149,7 +149,7 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data) dev_err(&client->dev, "Unable to write value 0x%02x to register 0x%02x.\n", data, reg); - }; + } return res; } @@ -1030,7 +1030,7 @@ static struct asc7621_data *asc7621_update_device(struct device *dev) } } data->last_high_reading = jiffies; - }; /* last_reading */ + } /* last_reading */ /* Read all the low priority registers. */ @@ -1044,7 +1044,7 @@ static struct asc7621_data *asc7621_update_device(struct device *dev) } } data->last_low_reading = jiffies; - }; /* last_reading */ + } /* last_reading */ data->valid = 1; @@ -1084,11 +1084,11 @@ static void asc7621_init_client(struct i2c_client *client) dev_err(&client->dev, "Client (%d,0x%02x) config is locked.\n", i2c_adapter_id(client->adapter), client->addr); - }; + } if (!(value & 0x04)) { dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", i2c_adapter_id(client->adapter), client->addr); - }; + } /* * Start monitoring diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index b25c64302cb..1d7ff46812c 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -119,7 +119,7 @@ struct atk_data { acpi_handle rtmp_handle; acpi_handle rvlt_handle; acpi_handle rfan_handle; - /* new inteface */ + /* new interface */ acpi_handle enumerate_handle; acpi_handle read_handle; acpi_handle write_handle; diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index aecb9ea7beb..ddff02e3e66 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -147,10 +147,9 @@ static ssize_t atxp1_storevcore(struct device *dev, /* Calculate VID */ vid = vid_to_reg(vcore, data->vrm); - if (vid < 0) { dev_err(dev, "VID calculation failed.\n"); - return -1; + return vid; } /* diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index a26ba7a17c2..872d76744e3 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -120,7 +120,7 @@ static const u8 DS1621_REG_TEMP[3] = { /* Each client has this additional data */ struct ds1621_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -151,10 +151,10 @@ static inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits) return temp; } -static void ds1621_init_client(struct i2c_client *client) +static void ds1621_init_client(struct ds1621_data *data, + struct i2c_client *client) { u8 conf, new_conf, sreg, resol; - struct ds1621_data *data = i2c_get_clientdata(client); new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); /* switch to continuous conversion mode */ @@ -197,8 +197,8 @@ static void ds1621_init_client(struct i2c_client *client) static struct ds1621_data *ds1621_update_client(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); + struct ds1621_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u8 new_conf; mutex_lock(&data->update_lock); @@ -247,8 +247,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); + struct ds1621_data *data = dev_get_drvdata(dev); long val; int err; @@ -258,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, mutex_lock(&data->update_lock); data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits); - i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index], + i2c_smbus_write_word_swapped(data->client, DS1621_REG_TEMP[attr->index], data->temp[attr->index]); mutex_unlock(&data->update_lock); return count; @@ -282,16 +281,15 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da, static ssize_t show_convrate(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); + struct ds1621_data *data = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval); } static ssize_t set_convrate(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); + struct ds1621_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long convrate; s32 err; int resol = 0; @@ -343,8 +341,7 @@ static umode_t ds1621_attribute_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); - struct i2c_client *client = to_i2c_client(dev); - struct ds1621_data *data = i2c_get_clientdata(client); + struct ds1621_data *data = dev_get_drvdata(dev); if (attr == &dev_attr_update_interval.attr) if (data->kind == ds1621 || data->kind == ds1625) @@ -357,52 +354,31 @@ static const struct attribute_group ds1621_group = { .attrs = ds1621_attributes, .is_visible = ds1621_attribute_visible }; +__ATTRIBUTE_GROUPS(ds1621); static int ds1621_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ds1621_data *data; - int err; + struct device *hwmon_dev; data = devm_kzalloc(&client->dev, sizeof(struct ds1621_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->kind = id->driver_data; + data->client = client; /* Initialize the DS1621 chip */ - ds1621_init_client(client); - - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &ds1621_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - - exit_remove_files: - sysfs_remove_group(&client->dev.kobj, &ds1621_group); - return err; -} - -static int ds1621_remove(struct i2c_client *client) -{ - struct ds1621_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &ds1621_group); + ds1621_init_client(data, client); - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + ds1621_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ds1621_id[] = { @@ -422,7 +398,6 @@ static struct i2c_driver ds1621_driver = { .name = "ds1621", }, .probe = ds1621_probe, - .remove = ds1621_remove, .id_table = ds1621_id, }; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 142e1cb8dea..90ec1173b8a 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -21,7 +21,6 @@ * * TODO * - cache alarm and critical limit registers - * - add emc1404 support */ #include <linux/module.h> @@ -40,7 +39,8 @@ #define THERMAL_REVISION_REG 0xff struct thermal_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex mutex; /* * Cache the hyst value so we don't keep re-reading it. In theory @@ -53,10 +53,11 @@ struct thermal_data { static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - int retval = i2c_smbus_read_byte_data(client, sda->index); + struct thermal_data *data = dev_get_drvdata(dev); + int retval; + retval = i2c_smbus_read_byte_data(data->client, sda->index); if (retval < 0) return retval; return sprintf(buf, "%d000\n", retval); @@ -65,27 +66,27 @@ static ssize_t show_temp(struct device *dev, static ssize_t show_bit(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); - int retval = i2c_smbus_read_byte_data(client, sda->nr); + struct thermal_data *data = dev_get_drvdata(dev); + int retval; + retval = i2c_smbus_read_byte_data(data->client, sda->nr); if (retval < 0) return retval; - retval &= sda->index; - return sprintf(buf, "%d\n", retval ? 1 : 0); + return sprintf(buf, "%d\n", !!(retval & sda->index)); } static ssize_t store_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct i2c_client *client = to_i2c_client(dev); + struct thermal_data *data = dev_get_drvdata(dev); unsigned long val; int retval; if (kstrtoul(buf, 10, &val)) return -EINVAL; - retval = i2c_smbus_write_byte_data(client, sda->index, + retval = i2c_smbus_write_byte_data(data->client, sda->index, DIV_ROUND_CLOSEST(val, 1000)); if (retval < 0) return retval; @@ -95,9 +96,9 @@ static ssize_t store_temp(struct device *dev, static ssize_t store_bit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); + struct thermal_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int retval; @@ -124,9 +125,9 @@ fail: static ssize_t show_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); + struct thermal_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int retval; int hyst; @@ -147,9 +148,9 @@ static ssize_t show_hyst(struct device *dev, static ssize_t store_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); + struct thermal_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int retval; int hyst; unsigned long val; @@ -232,10 +233,26 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_hyst, store_hyst, 0x1A); +static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x2D); +static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x2C); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x30); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A); +static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, + show_bit, NULL, 0x36, 0x08); +static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, + show_bit, NULL, 0x35, 0x08); +static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, + show_bit, NULL, 0x37, 0x08); +static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO | S_IWUSR, + show_hyst, store_hyst, 0x30); + static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, show_bit, store_bit, 0x03, 0x40); -static struct attribute *mid_att_thermal[] = { +static struct attribute *emc1403_attrs[] = { &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, @@ -264,8 +281,24 @@ static struct attribute *mid_att_thermal[] = { NULL }; -static const struct attribute_group m_thermal_gr = { - .attrs = mid_att_thermal +static const struct attribute_group emc1403_group = { + .attrs = emc1403_attrs, +}; + +static struct attribute *emc1404_attrs[] = { + &sensor_dev_attr_temp4_min.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, + NULL +}; + +static const struct attribute_group emc1404_group = { + .attrs = emc1404_attrs, }; static int emc1403_detect(struct i2c_client *client, @@ -286,10 +319,12 @@ static int emc1403_detect(struct i2c_client *client, case 0x23: strlcpy(info->type, "emc1423", I2C_NAME_SIZE); break; - /* - * Note: 0x25 is the 1404 which is very similar and this - * driver could be extended - */ + case 0x25: + strlcpy(info->type, "emc1404", I2C_NAME_SIZE); + break; + case 0x27: + strlcpy(info->type, "emc1424", I2C_NAME_SIZE); + break; default: return -ENODEV; } @@ -304,43 +339,29 @@ static int emc1403_detect(struct i2c_client *client, static int emc1403_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int res; struct thermal_data *data; + struct device *hwmon_dev; data = devm_kzalloc(&client->dev, sizeof(struct thermal_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->mutex); data->hyst_valid = jiffies - 1; /* Expired */ - res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr); - if (res) { - dev_warn(&client->dev, "create group failed\n"); - return res; - } - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - res = PTR_ERR(data->hwmon_dev); - dev_warn(&client->dev, "register hwmon dev failed\n"); - goto thermal_error; - } - dev_info(&client->dev, "EMC1403 Thermal chip found\n"); - return 0; - -thermal_error: - sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); - return res; -} + data->groups[0] = &emc1403_group; + if (id->driver_data) + data->groups[1] = &emc1404_group; -static int emc1403_remove(struct i2c_client *client) -{ - struct thermal_data *data = i2c_get_clientdata(client); + hwmon_dev = hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); + dev_info(&client->dev, "%s Thermal chip found\n", id->name); return 0; } @@ -350,7 +371,9 @@ static const unsigned short emc1403_address_list[] = { static const struct i2c_device_id emc1403_idtable[] = { { "emc1403", 0 }, + { "emc1404", 1 }, { "emc1423", 0 }, + { "emc1424", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); @@ -362,7 +385,6 @@ static struct i2c_driver sensor_emc1403 = { }, .detect = emc1403_detect, .probe = emc1403_probe, - .remove = emc1403_remove, .id_table = emc1403_idtable, .address_list = emc1403_address_list, }; diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 31b221eeee6..03d8592810b 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -2420,7 +2420,6 @@ static int f71882fg_probe(struct platform_device *pdev) exit_unregister_sysfs: f71882fg_remove(pdev); /* Will unregister the sysfs files for us */ return err; /* f71882fg_remove() also frees our data */ - return err; } static int f71882fg_remove(struct platform_device *pdev) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index a837b94977f..80c42bea90e 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -275,7 +275,7 @@ static bool duty_mode_enabled(u8 pwm_enable) case 3: /* Manual, speed mode */ return false; default: - BUG(); + WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); return true; } } @@ -291,7 +291,7 @@ static bool auto_mode_enabled(u8 pwm_enable) case 4: /* Auto, duty mode */ return true; default: - BUG(); + WARN(1, "Unexpected pwm_enable value %d\n", pwm_enable); return false; } } diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index b7d6a5704eb..73181be5b30 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -31,6 +31,7 @@ #include <linux/hwmon.h> #include <linux/gpio.h> #include <linux/gpio-fan.h> +#include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> @@ -169,7 +170,7 @@ static int get_fan_speed_index(struct gpio_fan_data *fan_data) dev_warn(&fan_data->pdev->dev, "missing speed array entry for GPIO value 0x%x\n", ctrl_val); - return -EINVAL; + return -ENODEV; } static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm) @@ -309,12 +310,6 @@ exit_unlock: return ret; } -static ssize_t show_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "gpio-fan\n"); -} - static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm); static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, set_pwm_enable); @@ -324,26 +319,23 @@ static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL); static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL); static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm); -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - static umode_t gpio_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); struct gpio_fan_data *data = dev_get_drvdata(dev); - if (index == 1 && !data->alarm) + if (index == 0 && !data->alarm) return 0; - if (index > 1 && !data->ctrl) + if (index > 0 && !data->ctrl) return 0; return attr->mode; } static struct attribute *gpio_fan_attributes[] = { - &dev_attr_name.attr, - &dev_attr_fan1_alarm.attr, /* 1 */ - &dev_attr_pwm1.attr, /* 2 */ + &dev_attr_fan1_alarm.attr, /* 0 */ + &dev_attr_pwm1.attr, /* 1 */ &dev_attr_pwm1_enable.attr, &dev_attr_pwm1_mode.attr, &dev_attr_fan1_input.attr, @@ -358,6 +350,11 @@ static const struct attribute_group gpio_fan_group = { .is_visible = gpio_fan_is_visible, }; +static const struct attribute_group *gpio_fan_groups[] = { + &gpio_fan_group, + NULL +}; + static int fan_ctrl_init(struct gpio_fan_data *fan_data, struct gpio_fan_platform_data *pdata) { @@ -384,7 +381,7 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data, fan_data->pwm_enable = true; /* Enable manual fan speed control. */ fan_data->speed_index = get_fan_speed_index(fan_data); if (fan_data->speed_index < 0) - return -ENODEV; + return fan_data->speed_index; return 0; } @@ -539,24 +536,16 @@ static int gpio_fan_probe(struct platform_device *pdev) return err; } - err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_group); - if (err) - return err; - /* Make this driver part of hwmon class. */ - fan_data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(fan_data->hwmon_dev)) { - err = PTR_ERR(fan_data->hwmon_dev); - goto err_remove; - } + fan_data->hwmon_dev = hwmon_device_register_with_groups(&pdev->dev, + "gpio-fan", fan_data, + gpio_fan_groups); + if (IS_ERR(fan_data->hwmon_dev)) + return PTR_ERR(fan_data->hwmon_dev); dev_info(&pdev->dev, "GPIO fan initialized\n"); return 0; - -err_remove: - sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group); - return err; } static int gpio_fan_remove(struct platform_device *pdev) @@ -564,7 +553,6 @@ static int gpio_fan_remove(struct platform_device *pdev) struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); hwmon_device_unregister(fan_data->hwmon_dev); - sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group); return 0; } diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 646314f7c83..e176a43af63 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/slab.h> #include <linux/kdev_t.h> #include <linux/idr.h> #include <linux/hwmon.h> @@ -25,35 +26,122 @@ #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" -static struct class *hwmon_class; +struct hwmon_device { + const char *name; + struct device dev; +}; +#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) + +static ssize_t +show_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); +} +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct attribute *hwmon_dev_attrs[] = { + &dev_attr_name.attr, + NULL +}; + +static umode_t hwmon_dev_name_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + + if (to_hwmon_device(dev)->name == NULL) + return 0; + + return attr->mode; +} + +static struct attribute_group hwmon_dev_attr_group = { + .attrs = hwmon_dev_attrs, + .is_visible = hwmon_dev_name_is_visible, +}; + +static const struct attribute_group *hwmon_dev_attr_groups[] = { + &hwmon_dev_attr_group, + NULL +}; + +static void hwmon_dev_release(struct device *dev) +{ + kfree(to_hwmon_device(dev)); +} + +static struct class hwmon_class = { + .name = "hwmon", + .owner = THIS_MODULE, + .dev_groups = hwmon_dev_attr_groups, + .dev_release = hwmon_dev_release, +}; static DEFINE_IDA(hwmon_ida); /** - * hwmon_device_register - register w/ hwmon - * @dev: the device to register + * hwmon_device_register_with_groups - register w/ hwmon + * @dev: the parent device + * @name: hwmon name attribute + * @drvdata: driver data to attach to created device + * @groups: List of attribute groups to create * * hwmon_device_unregister() must be called when the device is no * longer needed. * * Returns the pointer to the new device. */ -struct device *hwmon_device_register(struct device *dev) +struct device * +hwmon_device_register_with_groups(struct device *dev, const char *name, + void *drvdata, + const struct attribute_group **groups) { - struct device *hwdev; - int id; + struct hwmon_device *hwdev; + int err, id; id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); if (id < 0) return ERR_PTR(id); - hwdev = device_create(hwmon_class, dev, MKDEV(0, 0), NULL, - HWMON_ID_FORMAT, id); + hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL); + if (hwdev == NULL) { + err = -ENOMEM; + goto ida_remove; + } - if (IS_ERR(hwdev)) - ida_simple_remove(&hwmon_ida, id); + hwdev->name = name; + hwdev->dev.class = &hwmon_class; + hwdev->dev.parent = dev; + hwdev->dev.groups = groups; + hwdev->dev.of_node = dev ? dev->of_node : NULL; + dev_set_drvdata(&hwdev->dev, drvdata); + dev_set_name(&hwdev->dev, HWMON_ID_FORMAT, id); + err = device_register(&hwdev->dev); + if (err) + goto free; - return hwdev; + return &hwdev->dev; + +free: + kfree(hwdev); +ida_remove: + ida_simple_remove(&hwmon_ida, id); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); + +/** + * hwmon_device_register - register w/ hwmon + * @dev: the device to register + * + * hwmon_device_unregister() must be called when the device is no + * longer needed. + * + * Returns the pointer to the new device. + */ +struct device *hwmon_device_register(struct device *dev) +{ + return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); } EXPORT_SYMBOL_GPL(hwmon_device_register); @@ -75,6 +163,69 @@ void hwmon_device_unregister(struct device *dev) } EXPORT_SYMBOL_GPL(hwmon_device_unregister); +static void devm_hwmon_release(struct device *dev, void *res) +{ + struct device *hwdev = *(struct device **)res; + + hwmon_device_unregister(hwdev); +} + +/** + * devm_hwmon_device_register_with_groups - register w/ hwmon + * @dev: the parent device + * @name: hwmon name attribute + * @drvdata: driver data to attach to created device + * @groups: List of attribute groups to create + * + * Returns the pointer to the new device. The new device is automatically + * unregistered with the parent device. + */ +struct device * +devm_hwmon_device_register_with_groups(struct device *dev, const char *name, + void *drvdata, + const struct attribute_group **groups) +{ + struct device **ptr, *hwdev; + + if (!dev) + return ERR_PTR(-EINVAL); + + ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups); + if (IS_ERR(hwdev)) + goto error; + + *ptr = hwdev; + devres_add(dev, ptr); + return hwdev; + +error: + devres_free(ptr); + return hwdev; +} +EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); + +static int devm_hwmon_match(struct device *dev, void *res, void *data) +{ + struct device **hwdev = res; + + return *hwdev == data; +} + +/** + * devm_hwmon_device_unregister - removes a previously registered hwmon device + * + * @dev: the parent device of the device to unregister + */ +void devm_hwmon_device_unregister(struct device *dev) +{ + WARN_ON(devres_release(dev, devm_hwmon_release, devm_hwmon_match, dev)); +} +EXPORT_SYMBOL_GPL(devm_hwmon_device_unregister); + static void __init hwmon_pci_quirks(void) { #if defined CONFIG_X86 && defined CONFIG_PCI @@ -105,19 +256,21 @@ static void __init hwmon_pci_quirks(void) static int __init hwmon_init(void) { + int err; + hwmon_pci_quirks(); - hwmon_class = class_create(THIS_MODULE, "hwmon"); - if (IS_ERR(hwmon_class)) { - pr_err("couldn't create sysfs class\n"); - return PTR_ERR(hwmon_class); + err = class_register(&hwmon_class); + if (err) { + pr_err("couldn't register hwmon sysfs class\n"); + return err; } return 0; } static void __exit hwmon_exit(void) { - class_destroy(hwmon_class); + class_unregister(&hwmon_class); } subsys_initcall(hwmon_init); diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index c6fdd5bd395..5378fdefc1f 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -63,7 +63,7 @@ #define INA209_SHUNT_DEFAULT 10000 /* uOhm */ struct ina209_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; @@ -78,8 +78,8 @@ struct ina209_data { static struct ina209_data *ina209_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ina209_data *data = i2c_get_clientdata(client); + struct ina209_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct ina209_data *ret = data; s32 val; int i; @@ -234,7 +234,6 @@ static ssize_t ina209_set_interval(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); struct ina209_data *data = ina209_update_device(dev); long val; u16 regval; @@ -250,7 +249,8 @@ static ssize_t ina209_set_interval(struct device *dev, mutex_lock(&data->update_lock); regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION], val); - i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval); + i2c_smbus_write_word_swapped(data->client, INA209_CONFIGURATION, + regval); data->regs[INA209_CONFIGURATION] = regval; data->update_interval = ina209_interval_from_reg(regval); mutex_unlock(&data->update_lock); @@ -260,8 +260,7 @@ static ssize_t ina209_set_interval(struct device *dev, static ssize_t ina209_show_interval(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct ina209_data *data = i2c_get_clientdata(client); + struct ina209_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval); } @@ -285,9 +284,9 @@ static ssize_t ina209_reset_history(struct device *dev, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct ina209_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ina209_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u32 mask = attr->index; long val; int i, ret; @@ -312,7 +311,6 @@ static ssize_t ina209_set_value(struct device *dev, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); struct ina209_data *data = ina209_update_device(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); int reg = attr->index; @@ -332,7 +330,7 @@ static ssize_t ina209_set_value(struct device *dev, count = ret; goto abort; } - i2c_smbus_write_word_swapped(client, reg, ret); + i2c_smbus_write_word_swapped(data->client, reg, ret); data->regs[reg] = ret; abort: mutex_unlock(&data->update_lock); @@ -457,7 +455,7 @@ static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, * Finally, construct an array of pointers to members of the above objects, * as required for sysfs_create_group() */ -static struct attribute *ina209_attributes[] = { +static struct attribute *ina209_attrs[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_input_highest.dev_attr.attr, &sensor_dev_attr_in0_input_lowest.dev_attr.attr, @@ -498,10 +496,7 @@ static struct attribute *ina209_attributes[] = { NULL, }; - -static const struct attribute_group ina209_group = { - .attrs = ina209_attributes, -}; +ATTRIBUTE_GROUPS(ina209); static void ina209_restore_conf(struct i2c_client *client, struct ina209_data *data) @@ -565,6 +560,7 @@ static int ina209_probe(struct i2c_client *client, { struct i2c_adapter *adapter = client->adapter; struct ina209_data *data; + struct device *hwmon_dev; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) @@ -575,27 +571,23 @@ static int ina209_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); ret = ina209_init_client(client, data); if (ret) return ret; - /* Register sysfs hooks */ - ret = sysfs_create_group(&client->dev.kobj, &ina209_group); - if (ret) + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, + data, ina209_groups); + if (IS_ERR(hwmon_dev)) { + ret = PTR_ERR(hwmon_dev); goto out_restore_conf; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto out_hwmon_device_register; } return 0; -out_hwmon_device_register: - sysfs_remove_group(&client->dev.kobj, &ina209_group); out_restore_conf: ina209_restore_conf(client, data); return ret; @@ -605,8 +597,6 @@ static int ina209_remove(struct i2c_client *client) { struct ina209_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &ina209_group); ina209_restore_conf(client, data); return 0; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 70a39a8ac01..93d26e8af3e 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -78,7 +78,7 @@ struct ina2xx_config { }; struct ina2xx_data { - struct device *hwmon_dev; + struct i2c_client *client; const struct ina2xx_config *config; struct mutex update_lock; @@ -112,8 +112,8 @@ static const struct ina2xx_config ina2xx_config[] = { static struct ina2xx_data *ina2xx_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ina2xx_data *data = i2c_get_clientdata(client); + struct ina2xx_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct ina2xx_data *ret = data; mutex_lock(&data->update_lock); @@ -203,41 +203,39 @@ static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, INA2XX_POWER); /* pointers to created device attributes */ -static struct attribute *ina2xx_attributes[] = { +static struct attribute *ina2xx_attrs[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_curr1_input.dev_attr.attr, &sensor_dev_attr_power1_input.dev_attr.attr, NULL, }; - -static const struct attribute_group ina2xx_group = { - .attrs = ina2xx_attributes, -}; +ATTRIBUTE_GROUPS(ina2xx); static int ina2xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; - struct ina2xx_data *data; struct ina2xx_platform_data *pdata; - int ret; - u32 val; + struct device *dev = &client->dev; + struct ina2xx_data *data; + struct device *hwmon_dev; long shunt = 10000; /* default shunt value 10mOhms */ + u32 val; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - if (dev_get_platdata(&client->dev)) { - pdata = dev_get_platdata(&client->dev); + if (dev_get_platdata(dev)) { + pdata = dev_get_platdata(dev); shunt = pdata->shunt_uohms; - } else if (!of_property_read_u32(client->dev.of_node, - "shunt-resistor", &val)) { - shunt = val; + } else if (!of_property_read_u32(dev->of_node, + "shunt-resistor", &val)) { + shunt = val; } if (shunt <= 0) @@ -255,37 +253,18 @@ static int ina2xx_probe(struct i2c_client *client, i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION, data->config->calibration_factor / shunt); - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); - ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group); - if (ret) - return ret; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto out_err_hwmon; - } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, ina2xx_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - dev_info(&client->dev, "power monitor %s (Rshunt = %li uOhm)\n", + dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", id->name, shunt); return 0; - -out_err_hwmon: - sysfs_remove_group(&client->dev.kobj, &ina2xx_group); - return ret; -} - -static int ina2xx_remove(struct i2c_client *client) -{ - struct ina2xx_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &ina2xx_group); - - return 0; } static const struct i2c_device_id ina2xx_id[] = { @@ -302,7 +281,6 @@ static struct i2c_driver ina2xx_driver = { .name = "ina2xx", }, .probe = ina2xx_probe, - .remove = ina2xx_remove, .id_table = ina2xx_id, }; diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 4a58f130fd4..6013611e4f2 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -163,7 +163,7 @@ static struct jc42_chips jc42_chips[] = { /* Each client has this additional data */ struct jc42_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; /* protect register access */ bool extended; /* true if extended range supported */ bool valid; @@ -193,21 +193,21 @@ MODULE_DEVICE_TABLE(i2c, jc42_id); static int jc42_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct jc42_data *data = i2c_get_clientdata(client); + struct jc42_data *data = dev_get_drvdata(dev); data->config |= JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, data->config); + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); return 0; } static int jc42_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct jc42_data *data = i2c_get_clientdata(client); + struct jc42_data *data = dev_get_drvdata(dev); data->config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, data->config); + i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, + data->config); return 0; } @@ -317,15 +317,14 @@ static ssize_t set_##value(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct jc42_data *data = i2c_get_clientdata(client); \ + struct jc42_data *data = dev_get_drvdata(dev); \ int err, ret = count; \ long val; \ - if (kstrtol(buf, 10, &val) < 0) \ + if (kstrtol(buf, 10, &val) < 0) \ return -EINVAL; \ mutex_lock(&data->update_lock); \ data->value = jc42_temp_to_reg(val, data->extended); \ - err = i2c_smbus_write_word_swapped(client, reg, data->value); \ + err = i2c_smbus_write_word_swapped(data->client, reg, data->value); \ if (err < 0) \ ret = err; \ mutex_unlock(&data->update_lock); \ @@ -344,8 +343,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct jc42_data *data = i2c_get_clientdata(client); + struct jc42_data *data = dev_get_drvdata(dev); unsigned long val; int diff, hyst; int err; @@ -368,7 +366,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, mutex_lock(&data->update_lock); data->config = (data->config & ~JC42_CFG_HYST_MASK) | (hyst << JC42_CFG_HYST_SHIFT); - err = i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, + err = i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, data->config); if (err < 0) ret = err; @@ -430,8 +428,7 @@ static umode_t jc42_attribute_mode(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); - struct i2c_client *client = to_i2c_client(dev); - struct jc42_data *data = i2c_get_clientdata(client); + struct jc42_data *data = dev_get_drvdata(dev); unsigned int config = data->config; bool readonly; @@ -452,6 +449,7 @@ static const struct attribute_group jc42_group = { .attrs = jc42_attributes, .is_visible = jc42_attribute_mode, }; +__ATTRIBUTE_GROUPS(jc42); /* Return 0 if detection is successful, -ENODEV otherwise */ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -487,14 +485,16 @@ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info) static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct jc42_data *data; - int config, cap, err; struct device *dev = &client->dev; + struct device *hwmon_dev; + struct jc42_data *data; + int config, cap; data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL); if (!data) return -ENOMEM; + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); @@ -515,29 +515,15 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id) } data->config = config; - /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &jc42_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - sysfs_remove_group(&dev->kobj, &jc42_group); - return err; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + jc42_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static int jc42_remove(struct i2c_client *client) { struct jc42_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &jc42_group); /* Restore original configuration except hysteresis */ if ((data->config & ~JC42_CFG_HYST_MASK) != @@ -553,8 +539,8 @@ static int jc42_remove(struct i2c_client *client) static struct jc42_data *jc42_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct jc42_data *data = i2c_get_clientdata(client); + struct jc42_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct jc42_data *ret = data; int val; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 016efa26ba7..505a59e100b 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -174,7 +174,6 @@ out_dev_reg_failed: out_dev_create_file_failed: device_remove_file(&spi->dev, &dev_attr_temp1_input); out_dev_create_temp_file_failed: - spi_set_drvdata(spi, NULL); return status; } @@ -185,7 +184,6 @@ static int lm70_remove(struct spi_device *spi) hwmon_device_unregister(p_lm70->hwmon_dev); device_remove_file(&spi->dev, &dev_attr_temp1_input); device_remove_file(&spi->dev, &dev_attr_name); - spi_set_drvdata(spi, NULL); return 0; } diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 9bde9644b10..9653bb870a4 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -55,7 +55,7 @@ static const unsigned short lm73_convrates[] = { }; struct lm73_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex lock; u8 ctrl; /* control register value */ }; @@ -66,7 +66,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); + struct lm73_data *data = dev_get_drvdata(dev); long temp; short value; s32 err; @@ -77,7 +77,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, /* Write value */ value = clamp_val(temp / 250, LM73_TEMP_MIN, LM73_TEMP_MAX) << 5; - err = i2c_smbus_write_word_swapped(client, attr->index, value); + err = i2c_smbus_write_word_swapped(data->client, attr->index, value); return (err < 0) ? err : count; } @@ -85,10 +85,10 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); + struct lm73_data *data = dev_get_drvdata(dev); int temp; - s32 err = i2c_smbus_read_word_swapped(client, attr->index); + s32 err = i2c_smbus_read_word_swapped(data->client, attr->index); if (err < 0) return err; @@ -101,8 +101,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da, static ssize_t set_convrate(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm73_data *data = i2c_get_clientdata(client); + struct lm73_data *data = dev_get_drvdata(dev); unsigned long convrate; s32 err; int res = 0; @@ -124,7 +123,8 @@ static ssize_t set_convrate(struct device *dev, struct device_attribute *da, mutex_lock(&data->lock); data->ctrl &= LM73_CTRL_TO_MASK; data->ctrl |= res << LM73_CTRL_RES_SHIFT; - err = i2c_smbus_write_byte_data(client, LM73_REG_CTRL, data->ctrl); + err = i2c_smbus_write_byte_data(data->client, LM73_REG_CTRL, + data->ctrl); mutex_unlock(&data->lock); if (err < 0) @@ -136,8 +136,7 @@ static ssize_t set_convrate(struct device *dev, struct device_attribute *da, static ssize_t show_convrate(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm73_data *data = i2c_get_clientdata(client); + struct lm73_data *data = dev_get_drvdata(dev); int res; res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT; @@ -147,13 +146,12 @@ static ssize_t show_convrate(struct device *dev, struct device_attribute *da, static ssize_t show_maxmin_alarm(struct device *dev, struct device_attribute *da, char *buf) { - struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct lm73_data *data = i2c_get_clientdata(client); + struct lm73_data *data = dev_get_drvdata(dev); s32 ctrl; mutex_lock(&data->lock); - ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL); + ctrl = i2c_smbus_read_byte_data(data->client, LM73_REG_CTRL); if (ctrl < 0) goto abort; data->ctrl = ctrl; @@ -183,7 +181,7 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_maxmin_alarm, NULL, LM73_CTRL_LO_SHIFT); -static struct attribute *lm73_attributes[] = { +static struct attribute *lm73_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, @@ -192,10 +190,7 @@ static struct attribute *lm73_attributes[] = { &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm73_group = { - .attrs = lm73_attributes, -}; +ATTRIBUTE_GROUPS(lm73); /*-----------------------------------------------------------------------*/ @@ -204,16 +199,16 @@ static const struct attribute_group lm73_group = { static int lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int status; + struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm73_data *data; int ctrl; - data = devm_kzalloc(&client->dev, sizeof(struct lm73_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm73_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->lock); ctrl = i2c_smbus_read_byte_data(client, LM73_REG_CTRL); @@ -221,33 +216,13 @@ lm73_probe(struct i2c_client *client, const struct i2c_device_id *id) return ctrl; data->ctrl = ctrl; - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &lm73_group); - if (status) - return status; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm73_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - dev_info(&client->dev, "%s: sensor '%s'\n", - dev_name(data->hwmon_dev), client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &lm73_group); - return status; -} - -static int lm73_remove(struct i2c_client *client) -{ - struct lm73_data *data = i2c_get_clientdata(client); + dev_info(dev, "sensor '%s'\n", client->name); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm73_group); return 0; } @@ -300,7 +275,6 @@ static struct i2c_driver lm73_driver = { .name = "lm73", }, .probe = lm73_probe, - .remove = lm73_remove, .id_table = lm73_ids, .detect = lm73_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 307c9eaeeb9..411202bdaf6 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -57,7 +57,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END }; /* Client data (each client gets its own) */ struct lm95234_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; unsigned long last_updated, interval; /* in jiffies */ bool valid; /* false until following fields are valid */ @@ -114,9 +114,9 @@ static u16 update_intervals[] = { 143, 364, 1000, 2500 }; /* Fill value cache. Must be called with update lock held. */ -static int lm95234_fill_cache(struct i2c_client *client) +static int lm95234_fill_cache(struct lm95234_data *data, + struct i2c_client *client) { - struct lm95234_data *data = i2c_get_clientdata(client); int i, ret; ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE); @@ -157,9 +157,9 @@ static int lm95234_fill_cache(struct i2c_client *client) return 0; } -static int lm95234_update_device(struct i2c_client *client, - struct lm95234_data *data) +static int lm95234_update_device(struct lm95234_data *data) { + struct i2c_client *client = data->client; int ret; mutex_lock(&data->update_lock); @@ -169,7 +169,7 @@ static int lm95234_update_device(struct i2c_client *client, int i; if (!data->valid) { - ret = lm95234_fill_cache(client); + ret = lm95234_fill_cache(data, client); if (ret < 0) goto abort; } @@ -209,10 +209,9 @@ abort: static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -224,10 +223,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); u32 mask = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -238,10 +236,9 @@ static ssize_t show_alarm(struct device *dev, static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); u8 mask = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -252,11 +249,10 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, static ssize_t set_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); unsigned long val; u8 mask = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -274,7 +270,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr, else data->sensor_type &= ~mask; data->valid = false; - i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL, + i2c_smbus_write_byte_data(data->client, LM95234_REG_REM_MODEL, data->sensor_type); mutex_unlock(&data->update_lock); @@ -284,10 +280,9 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr, static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -298,11 +293,10 @@ static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr, static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; long val; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -315,7 +309,7 @@ static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->tcrit2[index] = val; - i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val); + i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT2(index), val); mutex_unlock(&data->update_lock); return count; @@ -324,10 +318,9 @@ static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr, static ssize_t show_tcrit2_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -340,8 +333,7 @@ static ssize_t show_tcrit2_hyst(struct device *dev, static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%u", data->tcrit1[index] * 1000); @@ -350,11 +342,10 @@ static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr, static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; + int ret = lm95234_update_device(data); long val; - int ret = lm95234_update_device(client, data); if (ret) return ret; @@ -367,7 +358,7 @@ static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->tcrit1[index] = val; - i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val); + i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT1(index), val); mutex_unlock(&data->update_lock); return count; @@ -376,10 +367,9 @@ static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr, static ssize_t show_tcrit1_hyst(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -393,11 +383,10 @@ static ssize_t set_tcrit1_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; + int ret = lm95234_update_device(data); long val; - int ret = lm95234_update_device(client, data); if (ret) return ret; @@ -411,7 +400,7 @@ static ssize_t set_tcrit1_hyst(struct device *dev, mutex_lock(&data->update_lock); data->thyst = val; - i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val); + i2c_smbus_write_byte_data(data->client, LM95234_REG_TCRIT_HYST, val); mutex_unlock(&data->update_lock); return count; @@ -420,10 +409,9 @@ static ssize_t set_tcrit1_hyst(struct device *dev, static ssize_t show_offset(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; - int ret = lm95234_update_device(client, data); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -434,11 +422,10 @@ static ssize_t show_offset(struct device *dev, struct device_attribute *attr, static ssize_t set_offset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(attr)->index; + int ret = lm95234_update_device(data); long val; - int ret = lm95234_update_device(client, data); if (ret) return ret; @@ -452,7 +439,7 @@ static ssize_t set_offset(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->toffset[index] = val; - i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val); + i2c_smbus_write_byte_data(data->client, LM95234_REG_OFFSET(index), val); mutex_unlock(&data->update_lock); return count; @@ -461,9 +448,8 @@ static ssize_t set_offset(struct device *dev, struct device_attribute *attr, static ssize_t show_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); - int ret = lm95234_update_device(client, data); + struct lm95234_data *data = dev_get_drvdata(dev); + int ret = lm95234_update_device(data); if (ret) return ret; @@ -475,11 +461,10 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr, static ssize_t set_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct lm95234_data *data = i2c_get_clientdata(client); + struct lm95234_data *data = dev_get_drvdata(dev); + int ret = lm95234_update_device(data); unsigned long val; u8 regval; - int ret = lm95234_update_device(client, data); if (ret) return ret; @@ -495,7 +480,7 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->interval = msecs_to_jiffies(update_intervals[regval]); - i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval); + i2c_smbus_write_byte_data(data->client, LM95234_REG_CONVRATE, regval); mutex_unlock(&data->update_lock); return count; @@ -579,7 +564,7 @@ static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset, static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, set_interval); -static struct attribute *lm95234_attributes[] = { +static struct attribute *lm95234_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, @@ -621,10 +606,7 @@ static struct attribute *lm95234_attributes[] = { &dev_attr_update_interval.attr, NULL }; - -static const struct attribute_group lm95234_group = { - .attrs = lm95234_attributes, -}; +ATTRIBUTE_GROUPS(lm95234); static int lm95234_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -701,13 +683,14 @@ static int lm95234_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct lm95234_data *data; + struct device *hwmon_dev; int err; data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM95234 chip */ @@ -715,32 +698,10 @@ static int lm95234_probe(struct i2c_client *client, if (err < 0) return err; - /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &lm95234_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&dev->kobj, &lm95234_group); - return err; -} - -static int lm95234_remove(struct i2c_client *client) -{ - struct lm95234_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm95234_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + lm95234_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* Driver data (common to all clients) */ @@ -756,7 +717,6 @@ static struct i2c_driver lm95234_driver = { .name = DRVNAME, }, .probe = lm95234_probe, - .remove = lm95234_remove, .id_table = lm95234_id, .detect = lm95234_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index cdc1ecc6734..d4172933ce4 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -51,7 +51,9 @@ enum ltc4245_cmd { }; struct ltc4245_data { - struct device *hwmon_dev; + struct i2c_client *client; + + const struct attribute_group *groups[3]; struct mutex update_lock; bool valid; @@ -77,8 +79,8 @@ struct ltc4245_data { */ static void ltc4245_update_gpios(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4245_data *data = i2c_get_clientdata(client); + struct ltc4245_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u8 gpio_curr, gpio_next, gpio_reg; int i; @@ -130,8 +132,8 @@ static void ltc4245_update_gpios(struct device *dev) static struct ltc4245_data *ltc4245_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4245_data *data = i2c_get_clientdata(client); + struct ltc4245_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; s32 val; int i; @@ -455,41 +457,14 @@ static const struct attribute_group ltc4245_gpio_group = { .attrs = ltc4245_gpio_attributes, }; -static int ltc4245_sysfs_create_groups(struct i2c_client *client) +static void ltc4245_sysfs_add_groups(struct ltc4245_data *data) { - struct ltc4245_data *data = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int ret; - - /* register the standard sysfs attributes */ - ret = sysfs_create_group(&dev->kobj, <c4245_std_group); - if (ret) { - dev_err(dev, "unable to register standard attributes\n"); - return ret; - } + /* standard sysfs attributes */ + data->groups[0] = <c4245_std_group; /* if we're using the extra gpio support, register it's attributes */ - if (data->use_extra_gpios) { - ret = sysfs_create_group(&dev->kobj, <c4245_gpio_group); - if (ret) { - dev_err(dev, "unable to register gpio attributes\n"); - sysfs_remove_group(&dev->kobj, <c4245_std_group); - return ret; - } - } - - return 0; -} - -static void ltc4245_sysfs_remove_groups(struct i2c_client *client) -{ - struct ltc4245_data *data = i2c_get_clientdata(client); - struct device *dev = &client->dev; - if (data->use_extra_gpios) - sysfs_remove_group(&dev->kobj, <c4245_gpio_group); - - sysfs_remove_group(&dev->kobj, <c4245_std_group); + data->groups[1] = <c4245_gpio_group; } static bool ltc4245_use_extra_gpios(struct i2c_client *client) @@ -517,7 +492,7 @@ static int ltc4245_probe(struct i2c_client *client, { struct i2c_adapter *adapter = client->adapter; struct ltc4245_data *data; - int ret; + struct device *hwmon_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -526,7 +501,7 @@ static int ltc4245_probe(struct i2c_client *client, if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); data->use_extra_gpios = ltc4245_use_extra_gpios(client); @@ -534,30 +509,25 @@ static int ltc4245_probe(struct i2c_client *client, i2c_smbus_write_byte_data(client, LTC4245_FAULT1, 0x00); i2c_smbus_write_byte_data(client, LTC4245_FAULT2, 0x00); - /* Register sysfs hooks */ - ret = ltc4245_sysfs_create_groups(client); - if (ret) - return ret; + /* Add sysfs hooks */ + ltc4245_sysfs_add_groups(data); - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto out_hwmon_device_register; - } + hwmon_dev = hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - return 0; + i2c_set_clientdata(client, hwmon_dev); -out_hwmon_device_register: - ltc4245_sysfs_remove_groups(client); - return ret; + return 0; } static int ltc4245_remove(struct i2c_client *client) { - struct ltc4245_data *data = i2c_get_clientdata(client); + struct device *hwmon_dev = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); - ltc4245_sysfs_remove_groups(client); + hwmon_device_unregister(hwmon_dev); return 0; } diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index 487da58ec86..0becd69842b 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -55,7 +55,7 @@ #define FAULT_OC (1<<2) struct ltc4261_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; @@ -67,8 +67,8 @@ struct ltc4261_data { static struct ltc4261_data *ltc4261_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct ltc4261_data *data = i2c_get_clientdata(client); + struct ltc4261_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct ltc4261_data *ret = data; mutex_lock(&data->update_lock); @@ -150,7 +150,6 @@ static ssize_t ltc4261_show_bool(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); struct ltc4261_data *data = ltc4261_update_device(dev); u8 fault; @@ -159,7 +158,7 @@ static ssize_t ltc4261_show_bool(struct device *dev, fault = data->regs[LTC4261_FAULT] & attr->index; if (fault) /* Clear reported faults in chip register */ - i2c_smbus_write_byte_data(client, LTC4261_FAULT, ~fault); + i2c_smbus_write_byte_data(data->client, LTC4261_FAULT, ~fault); return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0); } @@ -197,7 +196,7 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL, static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL, FAULT_OC); -static struct attribute *ltc4261_attributes[] = { +static struct attribute *ltc4261_attrs[] = { &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_min_alarm.dev_attr.attr, &sensor_dev_attr_in1_max_alarm.dev_attr.attr, @@ -210,62 +209,38 @@ static struct attribute *ltc4261_attributes[] = { NULL, }; - -static const struct attribute_group ltc4261_group = { - .attrs = ltc4261_attributes, -}; +ATTRIBUTE_GROUPS(ltc4261); static int ltc4261_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; + struct device *dev = &client->dev; struct ltc4261_data *data; - int ret; + struct device *hwmon_dev; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) { - dev_err(&client->dev, "Failed to read status register\n"); + dev_err(dev, "Failed to read status register\n"); return -ENODEV; } - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Clear faults */ i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00); - /* Register sysfs hooks */ - ret = sysfs_create_group(&client->dev.kobj, <c4261_group); - if (ret) - return ret; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - ret = PTR_ERR(data->hwmon_dev); - goto out_hwmon_device_register; - } - - return 0; - -out_hwmon_device_register: - sysfs_remove_group(&client->dev.kobj, <c4261_group); - return ret; -} - -static int ltc4261_remove(struct i2c_client *client) -{ - struct ltc4261_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, <c4261_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + ltc4261_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id ltc4261_id[] = { @@ -281,7 +256,6 @@ static struct i2c_driver ltc4261_driver = { .name = "ltc4261", }, .probe = ltc4261_probe, - .remove = ltc4261_remove, .id_table = ltc4261_id, }; diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index 2fa2c02f556..d4efc79d7b9 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -83,7 +83,8 @@ static const bool max16065_have_current[] = { struct max16065_data { enum chips type; - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[4]; struct mutex update_lock; bool valid; unsigned long last_updated; /* in jiffies */ @@ -144,8 +145,8 @@ static int max16065_read_adc(struct i2c_client *client, int reg) static struct max16065_data *max16065_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max16065_data *data = i2c_get_clientdata(client); + struct max16065_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { @@ -186,7 +187,7 @@ static ssize_t max16065_show_alarm(struct device *dev, val &= (1 << attr2->index); if (val) - i2c_smbus_write_byte_data(to_i2c_client(dev), + i2c_smbus_write_byte_data(data->client, MAX16065_FAULT(attr2->nr), val); return snprintf(buf, PAGE_SIZE, "%d\n", !!val); @@ -223,8 +224,7 @@ static ssize_t max16065_set_limit(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da); - struct i2c_client *client = to_i2c_client(dev); - struct max16065_data *data = i2c_get_clientdata(client); + struct max16065_data *data = dev_get_drvdata(dev); unsigned long val; int err; int limit; @@ -238,7 +238,7 @@ static ssize_t max16065_set_limit(struct device *dev, mutex_lock(&data->update_lock); data->limit[attr2->nr][attr2->index] = LIMIT_TO_MV(limit, data->range[attr2->index]); - i2c_smbus_write_byte_data(client, + i2c_smbus_write_byte_data(data->client, MAX16065_LIMIT(attr2->nr, attr2->index), limit); mutex_unlock(&data->update_lock); @@ -250,8 +250,7 @@ static ssize_t max16065_show_limit(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da); - struct i2c_client *client = to_i2c_client(dev); - struct max16065_data *data = i2c_get_clientdata(client); + struct max16065_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%d\n", data->limit[attr2->nr][attr2->index]); @@ -516,8 +515,32 @@ static struct attribute *max16065_max_attributes[] = { NULL }; +static umode_t max16065_basic_is_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct max16065_data *data = dev_get_drvdata(dev); + int index = n / 4; + + if (index >= data->num_adc || !data->range[index]) + return 0; + return a->mode; +} + +static umode_t max16065_secondary_is_visible(struct kobject *kobj, + struct attribute *a, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct max16065_data *data = dev_get_drvdata(dev); + + if (index >= data->num_adc) + return 0; + return a->mode; +} + static const struct attribute_group max16065_basic_group = { .attrs = max16065_basic_attributes, + .is_visible = max16065_basic_is_visible, }; static const struct attribute_group max16065_current_group = { @@ -526,38 +549,35 @@ static const struct attribute_group max16065_current_group = { static const struct attribute_group max16065_min_group = { .attrs = max16065_min_attributes, + .is_visible = max16065_secondary_is_visible, }; static const struct attribute_group max16065_max_group = { .attrs = max16065_max_attributes, + .is_visible = max16065_secondary_is_visible, }; -static void max16065_cleanup(struct i2c_client *client) -{ - sysfs_remove_group(&client->dev.kobj, &max16065_max_group); - sysfs_remove_group(&client->dev.kobj, &max16065_min_group); - sysfs_remove_group(&client->dev.kobj, &max16065_current_group); - sysfs_remove_group(&client->dev.kobj, &max16065_basic_group); -} - static int max16065_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = client->adapter; struct max16065_data *data; - int i, j, val, ret; + struct device *dev = &client->dev; + struct device *hwmon_dev; + int i, j, val; bool have_secondary; /* true if chip has secondary limits */ bool secondary_is_max = false; /* secondary limits reflect max */ + int groups = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_READ_WORD_DATA)) return -ENODEV; - data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (unlikely(!data)) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); data->num_adc = max16065_num_adc[id->driver_data]; @@ -596,38 +616,16 @@ static int max16065_probe(struct i2c_client *client, } } - /* Register sysfs hooks */ - for (i = 0; i < data->num_adc * 4; i++) { - /* Do not create sysfs entry if channel is disabled */ - if (!data->range[i / 4]) - continue; - - ret = sysfs_create_file(&client->dev.kobj, - max16065_basic_attributes[i]); - if (unlikely(ret)) - goto out; - } - - if (have_secondary) { - struct attribute **attr = secondary_is_max ? - max16065_max_attributes : max16065_min_attributes; - - for (i = 0; i < data->num_adc; i++) { - if (!data->range[i]) - continue; - - ret = sysfs_create_file(&client->dev.kobj, attr[i]); - if (unlikely(ret)) - goto out; - } - } + /* sysfs hooks */ + data->groups[groups++] = &max16065_basic_group; + if (have_secondary) + data->groups[groups++] = secondary_is_max ? + &max16065_max_group : &max16065_min_group; if (data->have_current) { val = i2c_smbus_read_byte_data(client, MAX16065_CURR_CONTROL); - if (unlikely(val < 0)) { - ret = val; - goto out; - } + if (unlikely(val < 0)) + return val; if (val & MAX16065_CURR_ENABLE) { /* * Current gain is 6, 12, 24, 48 based on values in @@ -636,33 +634,16 @@ static int max16065_probe(struct i2c_client *client, data->curr_gain = 6 << ((val >> 2) & 0x03); data->range[MAX16065_NUM_ADC] = max16065_csp_adc_range[(val >> 1) & 0x01]; - ret = sysfs_create_group(&client->dev.kobj, - &max16065_current_group); - if (unlikely(ret)) - goto out; + data->groups[groups++] = &max16065_current_group; } else { data->have_current = false; } } - data->hwmon_dev = hwmon_device_register(&client->dev); - if (unlikely(IS_ERR(data->hwmon_dev))) { - ret = PTR_ERR(data->hwmon_dev); - goto out; - } - return 0; - -out: - max16065_cleanup(client); - return ret; -} - -static int max16065_remove(struct i2c_client *client) -{ - struct max16065_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - max16065_cleanup(client); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + if (unlikely(IS_ERR(hwmon_dev))) + return PTR_ERR(hwmon_dev); return 0; } @@ -685,7 +666,6 @@ static struct i2c_driver max16065_driver = { .name = "max16065", }, .probe = max16065_probe, - .remove = max16065_remove, .id_table = max16065_id, }; diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 57d58cd3220..8326fbd6015 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -87,7 +87,7 @@ static int temp_to_reg(int val) */ struct max6642_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; bool valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -102,10 +102,10 @@ struct max6642_data { * Real code */ -static void max6642_init_client(struct i2c_client *client) +static void max6642_init_client(struct max6642_data *data, + struct i2c_client *client) { u8 config; - struct max6642_data *data = i2c_get_clientdata(client); /* * Start the conversions. @@ -168,14 +168,14 @@ static int max6642_detect(struct i2c_client *client, static struct max6642_data *max6642_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max6642_data *data = i2c_get_clientdata(client); + struct max6642_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; u16 val, tmp; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - dev_dbg(&client->dev, "Updating max6642 data.\n"); + dev_dbg(dev, "Updating max6642 data.\n"); val = i2c_smbus_read_byte_data(client, MAX6642_REG_R_LOCAL_TEMPL); tmp = (val >> 6) & 3; @@ -209,8 +209,8 @@ static struct max6642_data *max6642_update_device(struct device *dev) static ssize_t show_temp_max10(struct device *dev, struct device_attribute *dev_attr, char *buf) { - struct max6642_data *data = max6642_update_device(dev); struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct max6642_data *data = max6642_update_device(dev); return sprintf(buf, "%d\n", temp_from_reg10(data->temp_input[attr->index])); @@ -219,8 +219,8 @@ static ssize_t show_temp_max10(struct device *dev, static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, char *buf) { - struct max6642_data *data = max6642_update_device(dev); struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr); + struct max6642_data *data = max6642_update_device(dev); return sprintf(buf, "%d\n", temp_from_reg(data->temp_high[attr2->nr])); } @@ -228,11 +228,10 @@ static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr); + struct max6642_data *data = dev_get_drvdata(dev); unsigned long val; int err; - struct i2c_client *client = to_i2c_client(dev); - struct max6642_data *data = i2c_get_clientdata(client); - struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr); err = kstrtoul(buf, 10, &val); if (err < 0) @@ -240,7 +239,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->temp_high[attr2->nr] = clamp_val(temp_to_reg(val), 0, 255); - i2c_smbus_write_byte_data(client, attr2->index, + i2c_smbus_write_byte_data(data->client, attr2->index, data->temp_high[attr2->nr]); mutex_unlock(&data->update_lock); return count; @@ -264,7 +263,7 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); -static struct attribute *max6642_attributes[] = { +static struct attribute *max6642_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, @@ -275,54 +274,29 @@ static struct attribute *max6642_attributes[] = { &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, NULL }; +ATTRIBUTE_GROUPS(max6642); -static const struct attribute_group max6642_group = { - .attrs = max6642_attributes, -}; - -static int max6642_probe(struct i2c_client *new_client, +static int max6642_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct max6642_data *data; - int err; + struct device *hwmon_dev; - data = devm_kzalloc(&new_client->dev, sizeof(struct max6642_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct max6642_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(new_client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the MAX6642 chip */ - max6642_init_client(new_client); + max6642_init_client(data, client); - /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &max6642_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &max6642_group); - return err; -} - -static int max6642_remove(struct i2c_client *client) -{ - struct max6642_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &max6642_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + max6642_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } /* @@ -341,7 +315,6 @@ static struct i2c_driver max6642_driver = { .name = "max6642", }, .probe = max6642_probe, - .remove = max6642_remove, .id_table = max6642_id, .detect = max6642_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 3c16cbd4c00..0cafc390db4 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -660,7 +660,7 @@ static int max6650_init_client(struct i2c_client *client) /* * If mode is set to "full off", we change it to "open loop" and * set DAC to 255, which has the same effect. We do this because - * there's no "full off" mode defined in hwmon specifcations. + * there's no "full off" mode defined in hwmon specifications. */ if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) { diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index a41b5f3fc50..7fd3eaf817f 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -77,7 +77,7 @@ struct max6697_chip_data { }; struct max6697_data { - struct device *hwmon_dev; + struct i2c_client *client; enum chips type; const struct max6697_chip_data *chip; @@ -181,8 +181,8 @@ static const struct max6697_chip_data max6697_chip_data[] = { static struct max6697_data *max6697_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct max6697_data *data = i2c_get_clientdata(client); + struct max6697_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct max6697_data *ret = data; int val; int i; @@ -303,8 +303,7 @@ static ssize_t set_temp(struct device *dev, { int nr = to_sensor_dev_attr_2(devattr)->nr; int index = to_sensor_dev_attr_2(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct max6697_data *data = i2c_get_clientdata(client); + struct max6697_data *data = dev_get_drvdata(dev); long temp; int ret; @@ -316,7 +315,7 @@ static ssize_t set_temp(struct device *dev, temp = DIV_ROUND_CLOSEST(temp, 1000) + data->temp_offset; temp = clamp_val(temp, 0, data->type == max6581 ? 255 : 127); data->temp[nr][index] = temp; - ret = i2c_smbus_write_byte_data(client, + ret = i2c_smbus_write_byte_data(data->client, index == 2 ? MAX6697_REG_MAX[nr] : MAX6697_REG_CRIT[nr], temp); @@ -405,8 +404,7 @@ static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr, int index) { struct device *dev = container_of(kobj, struct device, kobj); - struct i2c_client *client = to_i2c_client(dev); - struct max6697_data *data = i2c_get_clientdata(client); + struct max6697_data *data = dev_get_drvdata(dev); const struct max6697_chip_data *chip = data->chip; int channel = index / 6; /* channel number */ int nr = index % 6; /* attribute index within channel */ @@ -489,6 +487,7 @@ static struct attribute *max6697_attributes[] = { static const struct attribute_group max6697_group = { .attrs = max6697_attributes, .is_visible = max6697_is_visible, }; +__ATTRIBUTE_GROUPS(max6697); static void max6697_get_config_of(struct device_node *node, struct max6697_platform_data *pdata) @@ -525,9 +524,9 @@ static void max6697_get_config_of(struct device_node *node, } } -static int max6697_init_chip(struct i2c_client *client) +static int max6697_init_chip(struct max6697_data *data, + struct i2c_client *client) { - struct max6697_data *data = i2c_get_clientdata(client); struct max6697_platform_data *pdata = dev_get_platdata(&client->dev); struct max6697_platform_data p; const struct max6697_chip_data *chip = data->chip; @@ -625,6 +624,7 @@ static int max6697_probe(struct i2c_client *client, struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; struct max6697_data *data; + struct device *hwmon_dev; int err; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -636,39 +636,17 @@ static int max6697_probe(struct i2c_client *client, data->type = id->driver_data; data->chip = &max6697_chip_data[data->type]; - - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); - err = max6697_init_chip(client); - if (err) - return err; - - err = sysfs_create_group(&client->dev.kobj, &max6697_group); + err = max6697_init_chip(data, client); if (err) return err; - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error; - } - - return 0; - -error: - sysfs_remove_group(&client->dev.kobj, &max6697_group); - return err; -} - -static int max6697_remove(struct i2c_client *client) -{ - struct max6697_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &max6697_group); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, + max6697_groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } static const struct i2c_device_id max6697_id[] = { @@ -692,7 +670,6 @@ static struct i2c_driver max6697_driver = { .name = "max6697", }, .probe = max6697_probe, - .remove = max6697_remove, .id_table = max6697_id, }; diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 982d8622c09..ae00e60d856 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -37,7 +37,7 @@ struct mc13783_adc_priv { struct mc13xxx *mc13xxx; struct device *hwmon_dev; - char name[10]; + char name[PLATFORM_NAME_SIZE]; }; static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 6eb03ce2cff..d17325db0ea 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -724,11 +724,8 @@ struct nct6775_data { enum kinds kind; const char *name; - struct device *hwmon_dev; - struct attribute_group *group_in; - struct attribute_group *group_fan; - struct attribute_group *group_temp; - struct attribute_group *group_pwm; + int num_attr_groups; + const struct attribute_group *groups[6]; u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst, * 3=temp_crit, 4=temp_lcrit @@ -942,7 +939,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, struct sensor_device_attribute_2 *a2; struct attribute **attrs; struct sensor_device_template **t; - int err, i, j, count; + int i, count; if (repeat <= 0) return ERR_PTR(-EINVAL); @@ -973,7 +970,7 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, for (i = 0; i < repeat; i++) { t = tg->templates; - for (j = 0; *t != NULL; j++) { + while (*t != NULL) { snprintf(su->name, sizeof(su->name), (*t)->dev_attr.attr.name, tg->base + i); if ((*t)->s2) { @@ -1002,10 +999,6 @@ nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg, } } - err = sysfs_create_group(&dev->kobj, group); - if (err) - return ERR_PTR(-ENOMEM); - return group; } @@ -1457,7 +1450,8 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) = nct6775_read_temp(data, data->reg_temp[j][i]); } - if (!(data->have_temp_fixed & (1 << i))) + if (i >= NUM_TEMP_FIXED || + !(data->have_temp_fixed & (1 << i))) continue; data->temp_offset[i] = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]); @@ -1545,7 +1539,7 @@ static int find_temp_source(struct nct6775_data *data, int index, int count) if (src == source) return nr; } - return -1; + return -ENODEV; } static ssize_t @@ -1644,7 +1638,7 @@ store_temp_beep(struct device *dev, struct device_attribute *attr, nr = find_temp_source(data, sattr->index, data->num_temp_beeps); if (nr < 0) - return -ENODEV; + return nr; bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE]; regindex = bit >> 3; @@ -2726,16 +2720,6 @@ store_fan_time(struct device *dev, struct device_attribute *attr, } static ssize_t -show_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct nct6775_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", data->name); -} - -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - -static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf) { struct nct6775_data *data = nct6775_update_device(dev); @@ -3061,16 +3045,16 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj, struct device *dev = container_of(kobj, struct device, kobj); struct nct6775_data *data = dev_get_drvdata(dev); - if (index == 1 && !data->have_vid) + if (index == 0 && !data->have_vid) return 0; - if (index == 2 || index == 3) { - if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0) + if (index == 1 || index == 2) { + if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 1] < 0) return 0; } - if (index == 4 || index == 5) { - if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0) + if (index == 3 || index == 4) { + if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0) return 0; } @@ -3083,13 +3067,12 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj, * Any change in order or content must be matched. */ static struct attribute *nct6775_attributes_other[] = { - &dev_attr_name.attr, - &dev_attr_cpu0_vid.attr, /* 1 */ - &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 2 */ - &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 3 */ - &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 4 */ - &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 5 */ - &sensor_dev_attr_beep_enable.dev_attr.attr, /* 6 */ + &dev_attr_cpu0_vid.attr, /* 0 */ + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, /* 1 */ + &sensor_dev_attr_intrusion1_alarm.dev_attr.attr, /* 2 */ + &sensor_dev_attr_intrusion0_beep.dev_attr.attr, /* 3 */ + &sensor_dev_attr_intrusion1_beep.dev_attr.attr, /* 4 */ + &sensor_dev_attr_beep_enable.dev_attr.attr, /* 5 */ NULL }; @@ -3099,27 +3082,6 @@ static const struct attribute_group nct6775_group_other = { .is_visible = nct6775_other_is_visible, }; -/* - * Driver and device management - */ - -static void nct6775_device_remove_files(struct device *dev) -{ - struct nct6775_data *data = dev_get_drvdata(dev); - - if (data->group_pwm) - sysfs_remove_group(&dev->kobj, data->group_pwm); - if (data->group_in) - sysfs_remove_group(&dev->kobj, data->group_in); - if (data->group_fan) - sysfs_remove_group(&dev->kobj, data->group_fan); - if (data->group_temp) - sysfs_remove_group(&dev->kobj, data->group_temp); - - sysfs_remove_group(&dev->kobj, &nct6775_group_other); -} - -/* Get the monitoring functions started */ static inline void nct6775_init_device(struct nct6775_data *data) { int i; @@ -3296,6 +3258,7 @@ static int nct6775_probe(struct platform_device *pdev) int num_reg_temp; u8 cr2a; struct attribute_group *group; + struct device *hwmon_dev; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, @@ -3870,61 +3833,36 @@ static int nct6775_probe(struct platform_device *pdev) /* Register sysfs hooks */ group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group, data->pwm_num); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_pwm = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_in_template_group, fls(data->have_in)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_in = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_fan_template_group, fls(data->has_fan)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_fan = group; + if (IS_ERR(group)) + return PTR_ERR(group); + + data->groups[data->num_attr_groups++] = group; group = nct6775_create_attr_group(dev, &nct6775_temp_template_group, fls(data->have_temp)); - if (IS_ERR(group)) { - err = PTR_ERR(group); - goto exit_remove; - } - data->group_temp = group; - - err = sysfs_create_group(&dev->kobj, &nct6775_group_other); - if (err) - goto exit_remove; + if (IS_ERR(group)) + return PTR_ERR(group); - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - return 0; - -exit_remove: - nct6775_device_remove_files(dev); - return err; -} - -static int nct6775_remove(struct platform_device *pdev) -{ - struct nct6775_data *data = platform_get_drvdata(pdev); + data->groups[data->num_attr_groups++] = group; + data->groups[data->num_attr_groups++] = &nct6775_group_other; - hwmon_device_unregister(data->hwmon_dev); - nct6775_device_remove_files(&pdev->dev); - - return 0; + hwmon_dev = devm_hwmon_device_register_with_groups(dev, data->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); } #ifdef CONFIG_PM @@ -4013,7 +3951,6 @@ static struct platform_driver nct6775_driver = { .pm = NCT6775_DEV_PM_OPS, }, .probe = nct6775_probe, - .remove = nct6775_remove, }; static const char * const nct6775_sio_names[] __initconst = { @@ -4101,7 +4038,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) /* * when Super-I/O functions move to a separate file, the Super-I/O * bus will manage the lifetime of the device and this module will only keep - * track of the nct6775 driver. But since we platform_device_alloc(), we + * track of the nct6775 driver. But since we use platform_device_alloc(), we * must keep track of the device */ static struct platform_device *pdev[2]; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 6a9d6edaacb..a26b1d1d951 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -1,5 +1,5 @@ /* - * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066 + * Hardware monitoring driver for LM25056 / LM25063 / LM25066 / LM5064 / LM5066 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013 Guenter Roeck @@ -27,7 +27,7 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { lm25056, lm25066, lm5064, lm5066 }; +enum chips { lm25056, lm25063, lm25066, lm5064, lm5066 }; #define LM25066_READ_VAUX 0xd0 #define LM25066_MFR_READ_IIN 0xd1 @@ -52,6 +52,11 @@ enum chips { lm25056, lm25066, lm5064, lm5066 }; #define LM25056_MFR_STS_VAUX_OV_WARN (1 << 1) #define LM25056_MFR_STS_VAUX_UV_WARN (1 << 0) +/* LM25063 only */ + +#define LM25063_READ_VOUT_MAX 0xe5 +#define LM25063_READ_VOUT_MIN 0xe6 + struct __coeff { short m, b, R; }; @@ -59,7 +64,7 @@ struct __coeff { #define PSC_CURRENT_IN_L (PSC_NUM_CLASSES) #define PSC_POWER_L (PSC_NUM_CLASSES + 1) -static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = { +static struct __coeff lm25066_coeff[5][PSC_NUM_CLASSES + 2] = { [lm25056] = { [PSC_VOLTAGE_IN] = { .m = 16296, @@ -116,6 +121,36 @@ static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = { .m = 16, }, }, + [lm25063] = { + [PSC_VOLTAGE_IN] = { + .m = 16000, + .R = -2, + }, + [PSC_VOLTAGE_OUT] = { + .m = 16000, + .R = -2, + }, + [PSC_CURRENT_IN] = { + .m = 10000, + .R = -2, + }, + [PSC_CURRENT_IN_L] = { + .m = 10000, + .R = -2, + }, + [PSC_POWER] = { + .m = 5000, + .R = -3, + }, + [PSC_POWER_L] = { + .m = 5000, + .R = -3, + }, + [PSC_TEMPERATURE] = { + .m = 15596, + .R = -3, + }, + }, [lm5064] = { [PSC_VOLTAGE_IN] = { .m = 4611, @@ -178,6 +213,7 @@ static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = { struct lm25066_data { int id; + u16 rlimit; /* Maximum register value */ struct pmbus_driver_info info; }; @@ -200,6 +236,10 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) /* VIN: 6.14 mV VAUX: 293 uV LSB */ ret = DIV_ROUND_CLOSEST(ret * 293, 6140); break; + case lm25063: + /* VIN: 6.25 mV VAUX: 200.0 uV LSB */ + ret = DIV_ROUND_CLOSEST(ret * 20, 625); + break; case lm25066: /* VIN: 4.54 mV VAUX: 283.2 uV LSB */ ret = DIV_ROUND_CLOSEST(ret * 2832, 45400); @@ -253,6 +293,24 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) return ret; } +static int lm25063_read_word_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_VOUT_MAX: + ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MAX); + break; + case PMBUS_VIRT_READ_VOUT_MIN: + ret = pmbus_read_word_data(client, 0, LM25063_READ_VOUT_MIN); + break; + default: + ret = lm25066_read_word_data(client, page, reg); + break; + } + return ret; +} + static int lm25056_read_word_data(struct i2c_client *client, int page, int reg) { int ret; @@ -308,27 +366,34 @@ static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg) static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct lm25066_data *data = to_lm25066_data(info); int ret; switch (reg) { + case PMBUS_POUT_OP_FAULT_LIMIT: + case PMBUS_POUT_OP_WARN_LIMIT: case PMBUS_VOUT_UV_WARN_LIMIT: case PMBUS_OT_FAULT_LIMIT: case PMBUS_OT_WARN_LIMIT: + case PMBUS_IIN_OC_FAULT_LIMIT: case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VIN_OV_FAULT_LIMIT: case PMBUS_VIN_OV_WARN_LIMIT: - word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); + word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, reg, word); pmbus_clear_cache(client); break; case PMBUS_IIN_OC_WARN_LIMIT: - word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); + word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25066_MFR_IIN_OC_WARN_LIMIT, word); pmbus_clear_cache(client); break; case PMBUS_PIN_OP_WARN_LIMIT: - word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); + word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25066_MFR_PIN_OP_WARN_LIMIT, word); @@ -337,7 +402,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, case PMBUS_VIRT_VMON_UV_WARN_LIMIT: /* Adjust from VIN coefficients (for LM25056) */ word = DIV_ROUND_CLOSEST((int)word * 6140, 293); - word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); + word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25056_VAUX_UV_WARN_LIMIT, word); pmbus_clear_cache(client); @@ -345,7 +410,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, case PMBUS_VIRT_VMON_OV_WARN_LIMIT: /* Adjust from VIN coefficients (for LM25056) */ word = DIV_ROUND_CLOSEST((int)word * 6140, 293); - word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff); + word = ((s16)word < 0) ? 0 : clamp_val(word, 0, data->rlimit); ret = pmbus_write_word_data(client, 0, LM25056_VAUX_OV_WARN_LIMIT, word); pmbus_clear_cache(client); @@ -399,9 +464,16 @@ static int lm25066_probe(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_STATUS_VMON; info->read_word_data = lm25056_read_word_data; info->read_byte_data = lm25056_read_byte_data; + data->rlimit = 0x0fff; + } else if (data->id == lm25063) { + info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_POUT; + info->read_word_data = lm25063_read_word_data; + data->rlimit = 0xffff; } else { info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; info->read_word_data = lm25066_read_word_data; + data->rlimit = 0x0fff; } info->write_word_data = lm25066_write_word_data; @@ -432,6 +504,7 @@ static int lm25066_probe(struct i2c_client *client, static const struct i2c_device_id lm25066_id[] = { {"lm25056", lm25056}, + {"lm25063", lm25063}, {"lm25066", lm25066}, {"lm5064", lm5064}, {"lm5066", lm5066}, @@ -453,5 +526,5 @@ static struct i2c_driver lm25066_driver = { module_i2c_driver(lm25066_driver); MODULE_AUTHOR("Guenter Roeck"); -MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066"); +MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 586a89ef9e0..de3c152a1d9 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -1,5 +1,6 @@ /* - * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883 + * Hardware monitoring driver for LTC2974, LTC2977, LTC2978, LTC3880, + * and LTC3883 * * Copyright (c) 2011 Ericsson AB. * Copyright (c) 2013 Guenter Roeck @@ -27,7 +28,7 @@ #include <linux/i2c.h> #include "pmbus.h" -enum chips { ltc2974, ltc2978, ltc3880, ltc3883 }; +enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883 }; /* Common for all chips */ #define LTC2978_MFR_VOUT_PEAK 0xdd @@ -35,7 +36,7 @@ enum chips { ltc2974, ltc2978, ltc3880, ltc3883 }; #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_SPECIAL_ID 0xe7 -/* LTC2974 and LTC2978 */ +/* LTC2974, LCT2977, and LTC2978 */ #define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VIN_MIN 0xfc #define LTC2978_MFR_TEMPERATURE_MIN 0xfd @@ -53,8 +54,10 @@ enum chips { ltc2974, ltc2978, ltc3880, ltc3883 }; #define LTC3883_MFR_IIN_PEAK 0xe1 #define LTC2974_ID 0x0212 +#define LTC2977_ID 0x0130 #define LTC2978_ID_REV1 0x0121 #define LTC2978_ID_REV2 0x0122 +#define LTC2978A_ID 0x0124 #define LTC3880_ID 0x4000 #define LTC3880_ID_MASK 0xff00 #define LTC3883_ID 0x4300 @@ -363,6 +366,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, static const struct i2c_device_id ltc2978_id[] = { {"ltc2974", ltc2974}, + {"ltc2977", ltc2977}, {"ltc2978", ltc2978}, {"ltc3880", ltc3880}, {"ltc3883", ltc3883}, @@ -392,7 +396,10 @@ static int ltc2978_probe(struct i2c_client *client, if (chip_id == LTC2974_ID) { data->id = ltc2974; - } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { + } else if (chip_id == LTC2977_ID) { + data->id = ltc2977; + } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2 || + chip_id == LTC2978A_ID) { data->id = ltc2978; } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { data->id = ltc3880; @@ -438,6 +445,7 @@ static int ltc2978_probe(struct i2c_client *client, | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; } break; + case ltc2977: case ltc2978: info->read_word_data = ltc2978_read_word_data; info->pages = LTC2978_NUM_PAGES; diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 9319fcf142d..3cbf66e9d86 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -97,6 +97,7 @@ struct pmbus_data { int max_attributes; int num_attributes; struct attribute_group group; + const struct attribute_group *groups[2]; struct pmbus_sensor *sensors; @@ -156,7 +157,7 @@ EXPORT_SYMBOL_GPL(pmbus_write_byte); /* * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if - * a device specific mapping funcion exists and calls it if necessary. + * a device specific mapping function exists and calls it if necessary. */ static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value) { @@ -348,7 +349,7 @@ static struct _pmbus_status { static struct pmbus_data *pmbus_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); const struct pmbus_driver_info *info = data->info; struct pmbus_sensor *sensor; @@ -686,7 +687,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, if (!s1 && !s2) { ret = !!regval; } else if (!s1 || !s2) { - BUG(); + WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); return 0; } else { long v1, v2; @@ -733,7 +734,7 @@ static ssize_t pmbus_set_sensor(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); ssize_t rv = count; @@ -1768,22 +1769,16 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, goto out_kfree; } - /* Register sysfs hooks */ - ret = sysfs_create_group(&dev->kobj, &data->group); - if (ret) { - dev_err(dev, "Failed to create sysfs entries\n"); - goto out_kfree; - } - data->hwmon_dev = hwmon_device_register(dev); + data->groups[0] = &data->group; + data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, + data, data->groups); if (IS_ERR(data->hwmon_dev)) { ret = PTR_ERR(data->hwmon_dev); dev_err(dev, "Failed to register hwmon device\n"); - goto out_hwmon_device_register; + goto out_kfree; } return 0; -out_hwmon_device_register: - sysfs_remove_group(&dev->kobj, &data->group); out_kfree: kfree(data->group.attrs); return ret; @@ -1794,7 +1789,6 @@ int pmbus_do_remove(struct i2c_client *client) { struct pmbus_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &data->group); kfree(data->group.attrs); return 0; } diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index dfe6d9527ef..7fa6e7d0b9b 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -155,7 +155,8 @@ MODULE_DEVICE_TABLE(i2c, tmp401_id); */ struct tmp401_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -231,8 +232,8 @@ static int tmp401_update_device_reg16(struct i2c_client *client, static struct tmp401_data *tmp401_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp401_data *data = i2c_get_clientdata(client); + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; struct tmp401_data *ret = data; int i, val; unsigned long next_update; @@ -350,15 +351,12 @@ static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, { int nr = to_sensor_dev_attr_2(devattr)->nr; int index = to_sensor_dev_attr_2(devattr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct tmp401_data *data = tmp401_update_device(dev); + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; u16 reg; u8 regaddr; - if (IS_ERR(data)) - return PTR_ERR(data); - if (kstrtol(buf, 10, &val)) return -EINVAL; @@ -405,7 +403,7 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute val = clamp_val(val, temp - 255000, temp); reg = ((temp - val) + 500) / 1000; - i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST, + i2c_smbus_write_byte_data(data->client, TMP401_TEMP_CRIT_HYST, reg); data->temp_crit_hyst = reg; @@ -423,8 +421,8 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute static ssize_t reset_temp_history(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp401_data *data = i2c_get_clientdata(client); + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; long val; if (kstrtol(buf, 10, &val)) @@ -447,8 +445,7 @@ static ssize_t reset_temp_history(struct device *dev, static ssize_t show_update_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp401_data *data = i2c_get_clientdata(client); + struct tmp401_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->update_interval); } @@ -457,8 +454,8 @@ static ssize_t set_update_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct tmp401_data *data = i2c_get_clientdata(client); + struct tmp401_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err, rate; @@ -616,10 +613,10 @@ static const struct attribute_group tmp432_group = { * Begin non sysfs callback code (aka Real code) */ -static void tmp401_init_client(struct i2c_client *client) +static void tmp401_init_client(struct tmp401_data *data, + struct i2c_client *client) { int config, config_orig; - struct tmp401_data *data = i2c_get_clientdata(client); /* Set the conversion rate to 2 Hz */ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); @@ -705,77 +702,45 @@ static int tmp401_detect(struct i2c_client *client, return 0; } -static int tmp401_remove(struct i2c_client *client) -{ - struct device *dev = &client->dev; - struct tmp401_data *data = i2c_get_clientdata(client); - - if (data->hwmon_dev) - hwmon_device_unregister(data->hwmon_dev); - - sysfs_remove_group(&dev->kobj, &tmp401_group); - - if (data->kind == tmp411) - sysfs_remove_group(&dev->kobj, &tmp411_group); - - if (data->kind == tmp432) - sysfs_remove_group(&dev->kobj, &tmp432_group); - - return 0; -} - static int tmp401_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" }; struct device *dev = &client->dev; - int err; + struct device *hwmon_dev; struct tmp401_data *data; - const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" }; + int groups = 0; data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); data->kind = id->driver_data; /* Initialize the TMP401 chip */ - tmp401_init_client(client); + tmp401_init_client(data, client); /* Register sysfs hooks */ - err = sysfs_create_group(&dev->kobj, &tmp401_group); - if (err) - return err; + data->groups[groups++] = &tmp401_group; /* Register additional tmp411 sysfs hooks */ - if (data->kind == tmp411) { - err = sysfs_create_group(&dev->kobj, &tmp411_group); - if (err) - goto exit_remove; - } + if (data->kind == tmp411) + data->groups[groups++] = &tmp411_group; /* Register additional tmp432 sysfs hooks */ - if (data->kind == tmp432) { - err = sysfs_create_group(&dev->kobj, &tmp432_group); - if (err) - goto exit_remove; - } + if (data->kind == tmp432) + data->groups[groups++] = &tmp432_group; - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - data->hwmon_dev = NULL; - goto exit_remove; - } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); dev_info(dev, "Detected TI %s chip\n", names[data->kind]); return 0; - -exit_remove: - tmp401_remove(client); - return err; } static struct i2c_driver tmp401_driver = { @@ -784,7 +749,6 @@ static struct i2c_driver tmp401_driver = { .name = "tmp401", }, .probe = tmp401_probe, - .remove = tmp401_remove, .id_table = tmp401_id, .detect = tmp401_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index a3feee332e2..bdcf2dce5ec 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1043,7 +1043,7 @@ static struct sensor_device_attribute sda_temp_alarm[] = { SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), }; -/* get reatime status of all sensors items: voltage, temp, fan */ +/* get realtime status of all sensors items: voltage, temp, fan */ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 5febb43cb4c..df585808adb 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -579,7 +579,7 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr, return count; } -/* get reatime status of all sensors items: voltage, temp, fan */ +/* get realtime status of all sensors items: voltage, temp, fan */ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index b0c30a546ff..9d63d71214c 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -808,7 +808,7 @@ show_sf_ctrl(struct device *dev, struct device_attribute *attr, char *buf) if (nr == TEMP_FAN_MAP) { val = data->temp_fan_map[index]; } else if (nr == TEMP_PWM_ENABLE) { - /* +2 to transfrom into 2 and 3 to conform with sysfs intf */ + /* +2 to transform into 2 and 3 to conform with sysfs intf */ val = ((data->pwm_enable >> index) & 0x01) + 2; } else if (nr == TEMP_CRUISE) { val = TEMP_FROM_REG(data->temp_cruise[index] & 0x7f); @@ -1199,7 +1199,8 @@ static void w83793_init_client(struct i2c_client *client) static int watchdog_set_timeout(struct w83793_data *data, int timeout) { - int ret, mtimeout; + unsigned int mtimeout; + int ret; mtimeout = DIV_ROUND_UP(timeout, 60); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b2b8aa9adc0..3e5ea2c87a6 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -447,7 +447,7 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm) init_waitqueue_head(&cpm->i2c_wait); - cpm->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + cpm->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (!cpm->irq) return -EINVAL; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index ff3caa0c28c..f7444100f39 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -41,6 +41,8 @@ #include <asm/irq.h> #include <linux/io.h> #include <linux/i2c.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include "i2c-ibm_iic.h" diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index b80c76888ca..b6a741caf4f 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -17,6 +17,8 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/init.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/slab.h> diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 37e8cfad625..8c87f4a9793 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -27,6 +27,7 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/platform_device.h> +#include <linux/of_irq.h> #include <asm/prom.h> #include <asm/pmac_low_i2c.h> diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3f7f59cc8b5..8fb46aab2d8 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -722,13 +722,6 @@ config BLK_DEV_IDE_RAPIDE Say Y here if you want to support the Yellowstone RapIDE controller manufactured for use with Acorn computers. -config IDE_H8300 - tristate "H8300 IDE support" - depends on H8300 - default y - help - Enables the H8300 IDE driver. - config BLK_DEV_GAYLE tristate "Amiga Gayle IDE interface support" depends on AMIGA diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index af8d016c37e..a04ee82f1c8 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -78,8 +78,6 @@ obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o -obj-$(CONFIG_IDE_H8300) += ide-h8300.o - obj-$(CONFIG_IDE_GENERIC) += ide-generic.o obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o diff --git a/drivers/ide/ide-h8300.c b/drivers/ide/ide-h8300.c deleted file mode 100644 index 520f42c5445..00000000000 --- a/drivers/ide/ide-h8300.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * H8/300 generic IDE interface - */ - -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#define DRV_NAME "ide-h8300" - -#define bswap(d) \ -({ \ - u16 r; \ - __asm__("mov.b %w1,r1h\n\t" \ - "mov.b %x1,r1l\n\t" \ - "mov.w r1,%0" \ - :"=r"(r) \ - :"r"(d) \ - :"er1"); \ - (r); \ -}) - -static void mm_outsw(unsigned long addr, void *buf, u32 len) -{ - unsigned short *bp = (unsigned short *)buf; - for (; len > 0; len--, bp++) - *(volatile u16 *)addr = bswap(*bp); -} - -static void mm_insw(unsigned long addr, void *buf, u32 len) -{ - unsigned short *bp = (unsigned short *)buf; - for (; len > 0; len--, bp++) - *bp = bswap(*(volatile u16 *)addr); -} - -static void h8300_input_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); -} - -static void h8300_output_data(ide_drive_t *drive, struct ide_cmd *cmd, - void *buf, unsigned int len) -{ - mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); -} - -static const struct ide_tp_ops h8300_tp_ops = { - .exec_command = ide_exec_command, - .read_status = ide_read_status, - .read_altstatus = ide_read_altstatus, - .write_devctl = ide_write_devctl, - - .dev_select = ide_dev_select, - .tf_load = ide_tf_load, - .tf_read = ide_tf_read, - - .input_data = h8300_input_data, - .output_data = h8300_output_data, -}; - -#define H8300_IDE_GAP (2) - -static inline void hw_setup(struct ide_hw *hw) -{ - int i; - - memset(hw, 0, sizeof(*hw)); - for (i = 0; i <= 7; i++) - hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i; - hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT; - hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ; -} - -static const struct ide_port_info h8300_port_info = { - .tp_ops = &h8300_tp_ops, - .host_flags = IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA, - .chipset = ide_generic, -}; - -static int __init h8300_ide_init(void) -{ - struct ide_hw hw, *hws[] = { &hw }; - - printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n"); - - if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300")) - goto out_busy; - if (!request_region(CONFIG_H8300_IDE_ALT, H8300_IDE_GAP, "ide-h8300")) { - release_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8); - goto out_busy; - } - - hw_setup(&hw); - - return ide_host_add(&h8300_port_info, hws, 1, NULL); - -out_busy: - printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n"); - - return -EBUSY; -} - -module_init(h8300_ide_init); - -MODULE_LICENSE("GPL"); diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index fa6964d8681..f116d664b47 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -359,7 +359,7 @@ static int intel_idle(struct cpuidle_device *dev, if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); - if (!need_resched()) { + if (!current_set_polling_and_test()) { __monitor((void *)¤t_thread_info()->flags, 0, 0); smp_mb(); diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c index f34beb228d3..17ccba88d63 100644 --- a/drivers/input/misc/ixp4xx-beeper.c +++ b/drivers/input/misc/ixp4xx-beeper.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/gpio.h> #include <mach/hardware.h> MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); @@ -35,15 +36,12 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) spin_lock_irqsave(&beep_lock, flags); - if (count) { - gpio_line_config(pin, IXP4XX_GPIO_OUT); - gpio_line_set(pin, IXP4XX_GPIO_LOW); - + if (count) { + gpio_direction_output(pin, 0); *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; } else { - gpio_line_config(pin, IXP4XX_GPIO_IN); - gpio_line_set(pin, IXP4XX_GPIO_HIGH); - + gpio_direction_output(pin, 1); + gpio_direction_input(pin); *IXP4XX_OSRT2 = 0; } @@ -78,11 +76,13 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) { + unsigned int pin = (unsigned int) dev_id; + /* clear interrupt */ *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; /* flip the beeper output */ - *IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id); + gpio_set_value(pin, !gpio_get_value(pin)); return IRQ_HANDLED; } @@ -110,11 +110,15 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = ixp4xx_spkr_event; + err = gpio_request(dev->id, "ixp4-beeper"); + if (err) + goto err_free_device; + err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt, IRQF_NO_SUSPEND, "ixp4xx-beeper", (void *) dev->id); if (err) - goto err_free_device; + goto err_free_gpio; err = input_register_device(input_dev); if (err) @@ -126,6 +130,8 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) err_free_irq: free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); + err_free_gpio: + gpio_free(dev->id); err_free_device: input_free_device(input_dev); @@ -144,6 +150,7 @@ static int ixp4xx_spkr_remove(struct platform_device *dev) ixp4xx_spkr_control(pin, 0); free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); + gpio_free(dev->id); return 0; } diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 4b7662a17ae..dfbcd872f95 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -25,6 +25,7 @@ #include <linux/io.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #define DRIVER_NAME "xilinx_ps2" @@ -235,12 +236,12 @@ static void sxps2_close(struct serio *pserio) */ static int xps2_of_probe(struct platform_device *ofdev) { - struct resource r_irq; /* Interrupt resources */ struct resource r_mem; /* IO mem resources */ struct xps2data *drvdata; struct serio *serio; struct device *dev = &ofdev->dev; resource_size_t remap_size, phys_addr; + unsigned int irq; int error; dev_info(dev, "Device Tree Probing \'%s\'\n", @@ -254,7 +255,8 @@ static int xps2_of_probe(struct platform_device *ofdev) } /* Get IRQ for the device */ - if (!of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq)) { + irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + if (!irq) { dev_err(dev, "no IRQ found\n"); return -ENODEV; } @@ -267,7 +269,7 @@ static int xps2_of_probe(struct platform_device *ofdev) } spin_lock_init(&drvdata->lock); - drvdata->irq = r_irq.start; + drvdata->irq = irq; drvdata->serio = serio; drvdata->dev = dev; diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index 16c78f1c5ef..1693b8e7f26 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -49,9 +49,11 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/irqdomain.h> -#include <linux/irqchip/bcm2835.h> #include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" /* Put the bank and irq (32 bits) into the hwirq */ #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) @@ -93,6 +95,8 @@ struct armctrl_ic { }; static struct armctrl_ic intc __read_mostly; +static asmlinkage void __exception_irq_entry bcm2835_handle_irq( + struct pt_regs *regs); static void armctrl_mask_irq(struct irq_data *d) { @@ -164,17 +168,9 @@ static int __init armctrl_of_init(struct device_node *node, set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } } - return 0; -} - -static struct of_device_id irq_of_match[] __initconst = { - { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }, - { } -}; -void __init bcm2835_init_irq(void) -{ - of_irq_init(irq_of_match); + set_handle_irq(bcm2835_handle_irq); + return 0; } /* @@ -200,7 +196,7 @@ static void armctrl_handle_shortcut(int bank, struct pt_regs *regs, handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); } -asmlinkage void __exception_irq_entry bcm2835_handle_irq( +static asmlinkage void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs) { u32 stat, irq; @@ -222,3 +218,5 @@ asmlinkage void __exception_irq_entry bcm2835_handle_irq( } } } + +IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 875bbe4c962..72156c12303 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -300,6 +300,16 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA9685 + tristate "LED support for PCA9685 I2C chip" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to the PCA9685 + LED driver chip accessed via the I2C bus. + The PCA9685 offers 12-bit PWM (4095 levels of brightness) on + 16 individual channels. + config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 8979b0b2c85..3cd76dbd9be 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA9685) += leds-pca9685.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c index a502678cc7f..66d0a57db22 100644 --- a/drivers/leds/leds-blinkm.c +++ b/drivers/leds/leds-blinkm.c @@ -161,13 +161,10 @@ static ssize_t show_color_common(struct device *dev, char *buf, int color) switch (color) { case RED: return scnprintf(buf, PAGE_SIZE, "%02X\n", data->red); - break; case GREEN: return scnprintf(buf, PAGE_SIZE, "%02X\n", data->green); - break; case BLUE: return scnprintf(buf, PAGE_SIZE, "%02X\n", data->blue); - break; default: return -EINVAL; } diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c index 1f9d8e62d37..db3ba8b4251 100644 --- a/drivers/leds/leds-dac124s085.c +++ b/drivers/leds/leds-dac124s085.c @@ -101,7 +101,6 @@ eledcr: while (i--) led_classdev_unregister(&dac->leds[i].ldev); - spi_set_drvdata(spi, NULL); return ret; } @@ -115,8 +114,6 @@ static int dac124s085_remove(struct spi_device *spi) cancel_work_sync(&dac->leds[i].work); } - spi_set_drvdata(spi, NULL); - return 0; } diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index e8b01e57348..78b0e273a90 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/leds.h> +#include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -170,11 +171,11 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) int count, ret; /* count LEDs in this device, so we know how much to allocate */ - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count) return ERR_PTR(-ENODEV); - for_each_child_of_node(np, child) + for_each_available_child_of_node(np, child) if (of_get_gpio(child, 0) == -EPROBE_DEFER) return ERR_PTR(-EPROBE_DEFER); @@ -183,7 +184,7 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) if (!priv) return ERR_PTR(-ENOMEM); - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct gpio_led led = {}; enum of_gpio_flags flags; const char *state; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index fe3bcbb5747..6b553d9f426 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -29,6 +29,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/platform_data/leds-lp55xx.h> #include <linux/slab.h> diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 2585cfd5771..bf006f4e44a 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -17,6 +17,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/platform_data/leds-lp55xx.h> #include <linux/slab.h> diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 351825b96f1..9acc6bb7dee 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -20,6 +20,8 @@ #include <linux/module.h> #include <linux/platform_data/leds-lp55xx.h> #include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> #include "leds-lp55xx-common.h" @@ -165,6 +167,7 @@ static int lp55xx_init_led(struct lp55xx_led *led, led->led_current = pdata->led_config[chan].led_current; led->max_current = pdata->led_config[chan].max_current; led->chan_nr = pdata->led_config[chan].chan_nr; + led->cdev.default_trigger = pdata->led_config[chan].default_trigger; if (led->chan_nr >= max_channel) { dev_err(dev, "Use channel numbers between 0 and %d\n", @@ -406,18 +409,18 @@ int lp55xx_init_device(struct lp55xx_chip *chip) if (!pdata || !cfg) return -EINVAL; - if (pdata->setup_resources) { - ret = pdata->setup_resources(); + if (gpio_is_valid(pdata->enable_gpio)) { + ret = devm_gpio_request_one(dev, pdata->enable_gpio, + GPIOF_DIR_OUT, "lp5523_enable"); if (ret < 0) { - dev_err(dev, "setup resoure err: %d\n", ret); + dev_err(dev, "could not acquire enable gpio (err=%d)\n", + ret); goto err; } - } - if (pdata->enable) { - pdata->enable(0); + gpio_set_value(pdata->enable_gpio, 0); usleep_range(1000, 2000); /* Keep enable down at least 1ms */ - pdata->enable(1); + gpio_set_value(pdata->enable_gpio, 1); usleep_range(1000, 2000); /* 500us abs min. */ } @@ -458,11 +461,8 @@ void lp55xx_deinit_device(struct lp55xx_chip *chip) if (chip->clk) clk_disable_unprepare(chip->clk); - if (pdata->enable) - pdata->enable(0); - - if (pdata->release_resources) - pdata->release_resources(); + if (gpio_is_valid(pdata->enable_gpio)) + gpio_set_value(pdata->enable_gpio, 0); } EXPORT_SYMBOL_GPL(lp55xx_deinit_device); @@ -586,6 +586,8 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) of_property_read_string(child, "chan-name", &cfg[i].name); of_property_read_u8(child, "led-cur", &cfg[i].led_current); of_property_read_u8(child, "max-cur", &cfg[i].max_current); + cfg[i].default_trigger = + of_get_property(child, "linux,default-trigger", NULL); i++; } @@ -593,6 +595,8 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np) of_property_read_string(np, "label", &pdata->label); of_property_read_u8(np, "clock-mode", &pdata->clock_mode); + pdata->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); + /* LP8501 specific */ of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel); diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index 8d55a780ca4..f1c704f2243 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -18,6 +18,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/platform_data/leds-lp55xx.h> #include <linux/slab.h> diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 141f13438e8..c7a4230233e 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -30,6 +30,7 @@ #include <linux/leds.h> #include <linux/module.h> #include <linux/platform_data/leds-kirkwood-ns2.h> +#include <linux/of.h> #include <linux/of_gpio.h> /* diff --git a/drivers/leds/leds-pca9685.c b/drivers/leds/leds-pca9685.c new file mode 100644 index 00000000000..6e1ef3a9d6e --- /dev/null +++ b/drivers/leds/leds-pca9685.c @@ -0,0 +1,213 @@ +/* + * Copyright 2013 Maximilian Güntner <maximilian.guentner@gmail.com> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * Based on leds-pca963x.c driver by + * Peter Meerwald <p.meerwald@bct-electronic.com> + * + * Driver for the NXP PCA9685 12-Bit PWM LED driver chip. + * + */ + +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/workqueue.h> + +#include <linux/platform_data/leds-pca9685.h> + +/* Register Addresses */ +#define PCA9685_MODE1 0x00 +#define PCA9685_MODE2 0x01 +#define PCA9685_LED0_ON_L 0x06 +#define PCA9685_ALL_LED_ON_L 0xFA + +/* MODE1 Register */ +#define PCA9685_ALLCALL 0x00 +#define PCA9685_SLEEP 0x04 +#define PCA9685_AI 0x05 + +/* MODE2 Register */ +#define PCA9685_INVRT 0x04 +#define PCA9685_OUTDRV 0x02 + +static const struct i2c_device_id pca9685_id[] = { + { "pca9685", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pca9685_id); + +struct pca9685_led { + struct i2c_client *client; + struct work_struct work; + u16 brightness; + struct led_classdev led_cdev; + int led_num; /* 0-15 */ + char name[32]; +}; + +static void pca9685_write_msg(struct i2c_client *client, u8 *buf, u8 len) +{ + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0x00, + .len = len, + .buf = buf + }; + i2c_transfer(client->adapter, &msg, 1); +} + +static void pca9685_all_off(struct i2c_client *client) +{ + u8 i2c_buffer[5] = {PCA9685_ALL_LED_ON_L, 0x00, 0x00, 0x00, 0x10}; + pca9685_write_msg(client, i2c_buffer, 5); +} + +static void pca9685_led_work(struct work_struct *work) +{ + struct pca9685_led *pca9685; + u8 i2c_buffer[5]; + + pca9685 = container_of(work, struct pca9685_led, work); + i2c_buffer[0] = PCA9685_LED0_ON_L + 4 * pca9685->led_num; + /* + * 4095 is the maximum brightness, so we set the ON time to 0x1000 + * which disables the PWM generator for that LED + */ + if (pca9685->brightness == 4095) + *((__le16 *)(i2c_buffer+1)) = cpu_to_le16(0x1000); + else + *((__le16 *)(i2c_buffer+1)) = 0x0000; + + if (pca9685->brightness == 0) + *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(0x1000); + else if (pca9685->brightness == 4095) + *((__le16 *)(i2c_buffer+3)) = 0x0000; + else + *((__le16 *)(i2c_buffer+3)) = cpu_to_le16(pca9685->brightness); + + pca9685_write_msg(pca9685->client, i2c_buffer, 5); +} + +static void pca9685_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct pca9685_led *pca9685; + pca9685 = container_of(led_cdev, struct pca9685_led, led_cdev); + pca9685->brightness = value; + + schedule_work(&pca9685->work); +} + +static int pca9685_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pca9685_led *pca9685; + struct pca9685_platform_data *pdata; + int err; + u8 i; + + pdata = dev_get_platdata(&client->dev); + if (pdata) { + if (pdata->leds.num_leds < 1 || pdata->leds.num_leds > 15) { + dev_err(&client->dev, "board info must claim 1-16 LEDs"); + return -EINVAL; + } + } + + pca9685 = devm_kzalloc(&client->dev, 16 * sizeof(*pca9685), GFP_KERNEL); + if (!pca9685) + return -ENOMEM; + + i2c_set_clientdata(client, pca9685); + pca9685_all_off(client); + + for (i = 0; i < 16; i++) { + pca9685[i].client = client; + pca9685[i].led_num = i; + pca9685[i].name[0] = '\0'; + if (pdata && i < pdata->leds.num_leds) { + if (pdata->leds.leds[i].name) + strncpy(pca9685[i].name, + pdata->leds.leds[i].name, + sizeof(pca9685[i].name)-1); + if (pdata->leds.leds[i].default_trigger) + pca9685[i].led_cdev.default_trigger = + pdata->leds.leds[i].default_trigger; + } + if (strlen(pca9685[i].name) == 0) { + /* + * Write adapter and address to the name as well. + * Otherwise multiple chips attached to one host would + * not work. + */ + snprintf(pca9685[i].name, sizeof(pca9685[i].name), + "pca9685:%d:x%.2x:%d", + client->adapter->nr, client->addr, i); + } + pca9685[i].led_cdev.name = pca9685[i].name; + pca9685[i].led_cdev.max_brightness = 0xfff; + pca9685[i].led_cdev.brightness_set = pca9685_led_set; + + INIT_WORK(&pca9685[i].work, pca9685_led_work); + err = led_classdev_register(&client->dev, &pca9685[i].led_cdev); + if (err < 0) + goto exit; + } + + if (pdata) + i2c_smbus_write_byte_data(client, PCA9685_MODE2, + pdata->outdrv << PCA9685_OUTDRV | + pdata->inverted << PCA9685_INVRT); + else + i2c_smbus_write_byte_data(client, PCA9685_MODE2, + PCA9685_TOTEM_POLE << PCA9685_OUTDRV); + /* Enable Auto-Increment, enable oscillator, ALLCALL/SUBADDR disabled */ + i2c_smbus_write_byte_data(client, PCA9685_MODE1, BIT(PCA9685_AI)); + + return 0; + +exit: + while (i--) { + led_classdev_unregister(&pca9685[i].led_cdev); + cancel_work_sync(&pca9685[i].work); + } + return err; +} + +static int pca9685_remove(struct i2c_client *client) +{ + struct pca9685_led *pca9685 = i2c_get_clientdata(client); + u8 i; + + for (i = 0; i < 16; i++) { + led_classdev_unregister(&pca9685[i].led_cdev); + cancel_work_sync(&pca9685[i].work); + } + pca9685_all_off(client); + return 0; +} + +static struct i2c_driver pca9685_driver = { + .driver = { + .name = "leds-pca9685", + .owner = THIS_MODULE, + }, + .probe = pca9685_probe, + .remove = pca9685_remove, + .id_table = pca9685_id, +}; + +module_i2c_driver(pca9685_driver); + +MODULE_AUTHOR("Maximilian Güntner <maximilian.guentner@gmail.com>"); +MODULE_DESCRIPTION("PCA9685 LED Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index bb6f9489854..2848171b857 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -232,7 +232,7 @@ static struct platform_driver led_pwm_driver = { .driver = { .name = "leds_pwm", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(of_pwm_leds_match), + .of_match_table = of_pwm_leds_match, }, }; diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 696238b9f0f..d26a312f117 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -103,6 +103,7 @@ config ADB_PMU_LED_IDE bool "Use front LED as IDE LED by default" depends on ADB_PMU_LED depends on LEDS_CLASS + depends on IDE_GD_ATA select LEDS_TRIGGERS select LEDS_TRIGGER_IDE_DISK help diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c index ac5c8793986..4f12c6f01fe 100644 --- a/drivers/macintosh/macio_asic.c +++ b/drivers/macintosh/macio_asic.c @@ -24,6 +24,8 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/machdep.h> #include <asm/macio.h> diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index cad0e19b47a..4192901cab4 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -25,6 +25,8 @@ #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/kernel_stat.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/io.h> #include <asm/prom.h> diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index b3b2d36c009..23b4a3b28db 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -35,6 +35,7 @@ #include <linux/poll.h> #include <linux/mutex.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/slab.h> diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 283e1b53c6b..dee88e59f0d 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -46,6 +46,8 @@ #include <linux/suspend.h> #include <linux/cpu.h> #include <linux/compat.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index fe9898ca3c8..6a232239ee8 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -21,6 +21,8 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/slab.h> #include <media/v4l2-common.h> diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 5ac3aa48473..022b1863d36 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -569,13 +569,25 @@ static struct mfd_cell early_devs[] = { { .name = "arizona-ldo1" }, }; +static const char *wm5102_supplies[] = { + "DBVDD2", + "DBVDD3", + "CPVDD", + "SPKVDDL", + "SPKVDDR", +}; + static struct mfd_cell wm5102_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-extcon" }, { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, - { .name = "wm5102-codec" }, + { + .name = "wm5102-codec", + .parent_supplies = wm5102_supplies, + .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), + }, }; static struct mfd_cell wm5110_devs[] = { @@ -584,7 +596,17 @@ static struct mfd_cell wm5110_devs[] = { { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, - { .name = "wm5110-codec" }, + { + .name = "wm5110-codec", + .parent_supplies = wm5102_supplies, + .num_parent_supplies = ARRAY_SIZE(wm5102_supplies), + }, +}; + +static const char *wm8997_supplies[] = { + "DBVDD2", + "CPVDD", + "SPKVDD", }; static struct mfd_cell wm8997_devs[] = { @@ -593,7 +615,11 @@ static struct mfd_cell wm8997_devs[] = { { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, - { .name = "wm8997-codec" }, + { + .name = "wm8997-codec", + .parent_supplies = wm8997_supplies, + .num_parent_supplies = ARRAY_SIZE(wm8997_supplies), + }, }; int arizona_dev_init(struct arizona *arizona) diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 2a9b100c482..dbbf8ee3f59 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -158,8 +158,6 @@ int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) { int ret; - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - if (offset > MC13XXX_NUMREGS) return -EINVAL; @@ -172,8 +170,6 @@ EXPORT_SYMBOL(mc13xxx_reg_read); int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); - dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val); if (offset > MC13XXX_NUMREGS || val > 0xffffff) @@ -186,7 +182,6 @@ EXPORT_SYMBOL(mc13xxx_reg_write); int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, u32 mask, u32 val) { - BUG_ON(!mutex_is_locked(&mc13xxx->lock)); BUG_ON(val & ~mask); dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n", offset, val, mask); diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 77189daadf1..5f14ef6693c 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -94,10 +94,15 @@ static int mc13xxx_spi_write(void *context, const void *data, size_t count) { struct device *dev = context; struct spi_device *spi = to_spi_device(dev); + const char *reg = data; if (count != 4) return -ENOTSUPP; + /* include errata fix for spi audio problems */ + if (*reg == MC13783_AUDIO_CODEC || *reg == MC13783_AUDIO_DAC) + spi_write(spi, data, count); + return spi_write(spi, data, count); } diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index f421586f29f..adc8ea36e7c 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/irqdomain.h> #include <linux/of.h> +#include <linux/regulator/consumer.h> static struct device_type mfd_dev_type = { .name = "mfd_device", @@ -99,6 +100,13 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.dma_mask = parent->dma_mask; pdev->dev.dma_parms = parent->dma_parms; + ret = devm_regulator_bulk_register_supply_alias( + &pdev->dev, cell->parent_supplies, + parent, cell->parent_supplies, + cell->num_parent_supplies); + if (ret < 0) + goto fail_res; + if (parent->of_node && cell->of_compatible) { for_each_child_of_node(parent->of_node, np) { if (of_device_is_compatible(np, cell->of_compatible)) { @@ -112,12 +120,12 @@ static int mfd_add_device(struct device *parent, int id, ret = platform_device_add_data(pdev, cell->platform_data, cell->pdata_size); if (ret) - goto fail_res; + goto fail_alias; } ret = mfd_platform_add_cell(pdev, cell); if (ret) - goto fail_res; + goto fail_alias; for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; @@ -152,17 +160,17 @@ static int mfd_add_device(struct device *parent, int id, if (!cell->ignore_resource_conflicts) { ret = acpi_check_resource_conflict(&res[r]); if (ret) - goto fail_res; + goto fail_alias; } } ret = platform_device_add_resources(pdev, res, cell->num_resources); if (ret) - goto fail_res; + goto fail_alias; ret = platform_device_add(pdev); if (ret) - goto fail_res; + goto fail_alias; if (cell->pm_runtime_no_callbacks) pm_runtime_no_callbacks(&pdev->dev); @@ -171,6 +179,10 @@ static int mfd_add_device(struct device *parent, int id, return 0; +fail_alias: + devm_regulator_bulk_unregister_supply_alias(&pdev->dev, + cell->parent_supplies, + cell->num_parent_supplies); fail_res: kfree(res); fail_device: diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index c6bd7e84de2..7be89832db1 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -10,6 +10,8 @@ */ #include <linux/dma-mapping.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/completion.h> #include <linux/miscdevice.h> diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 7b56563f8b7..08b18f3f526 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c @@ -88,6 +88,8 @@ * interrupt source to the GPIO pin. Tada, we hid the interrupt. :) */ +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> #include <linux/miscdevice.h> diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 20657209a47..e59c8860f47 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/ioport.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 317a771f158..2730c78d2bf 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -24,6 +24,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/of_address.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 04e07252d74..4d203e84e8c 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -18,6 +18,7 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> #include <linux/mtd/mtd.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/io.h> diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 3c60a000b42..439bc389641 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -36,7 +36,9 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/mpc5121.h> diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 8e148f1478f..69eaba690a9 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -30,6 +30,7 @@ #include <linux/mtd/ndfc.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 5a67082c07e..4d174366a0f 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -28,6 +28,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pci.h> diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 09dde7d2717..49bd9155cb1 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -15,6 +15,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/io.h> diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 3a8c7532ee0..a7271e09384 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -102,8 +102,7 @@ static struct devprobe2 isa_probes[] __initdata = { #ifdef CONFIG_WD80x3 {wd_probe, 0}, #endif -#if defined(CONFIG_NE2000) || \ - defined(CONFIG_NE_H8300) /* ISA (use ne2k-pci for PCI cards) */ +#if defined(CONFIG_NE2000) /* ISA (use ne2k-pci for PCI cards) */ {ne_probe, 0}, #endif #ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */ diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 6aa737a2439..ab506d6cab3 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -34,10 +34,7 @@ #include <linux/io.h> #include <linux/can/dev.h> #include <linux/spinlock.h> - #include <linux/of_platform.h> -#include <asm/prom.h> - #include <linux/of_irq.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c index 31ad3391116..047accd4ede 100644 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ b/drivers/net/can/sja1000/sja1000_of_platform.c @@ -44,7 +44,6 @@ #include <linux/of_platform.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <asm/prom.h> #include "sja1000.h" diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index becef25fa19..0988811f4e4 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -146,13 +146,6 @@ config PCMCIA_PCNET To compile this driver as a module, choose M here: the module will be called pcnet_cs. If unsure, say N. -config NE_H8300 - tristate "NE2000 compatible support for H8/300" - depends on H8300H_AKI3068NET || H8300H_H8MAX - ---help--- - Say Y here if you want to use the NE2000 compatible - controller on the Renesas H8/300 processor. - config STNIC tristate "National DP83902AV support" depends on SUPERH diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index 588954a79b2..ff3b3189418 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_HYDRA) += hydra.o 8390.o obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o obj-$(CONFIG_NE2000) += ne.o 8390p.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o diff --git a/drivers/net/ethernet/8390/ne-h8300.c b/drivers/net/ethernet/8390/ne-h8300.c deleted file mode 100644 index 7fc28f2d28a..00000000000 --- a/drivers/net/ethernet/8390/ne-h8300.c +++ /dev/null @@ -1,684 +0,0 @@ -/* ne-h8300.c: A NE2000 clone on H8/300 driver for linux. */ -/* - original ne.c - Written 1992-94 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 - - H8/300 modified - Yoshinori Sato <ysato@users.sourceforge.jp> -*/ - -static const char version1[] = -"ne-h8300.c:v1.00 2004/04/11 ysato\n"; - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/jiffies.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#define EI_SHIFT(x) (ei_local->reg_offset[x]) - -#include "8390.h" - -#define DRV_NAME "ne-h8300" - -/* Some defines that people can play with if so inclined. */ - -/* Do we perform extra sanity checks on stuff ? */ -/* #define NE_SANITY_CHECK */ - -/* Do we implement the read before write bugfix ? */ -/* #define NE_RW_BUGFIX */ - -/* Do we have a non std. amount of memory? (in units of 256 byte pages) */ -/* #define PACKETBUF_MEMSIZE 0x40 */ - -/* A zero-terminated list of I/O addresses to be probed at boot. */ - -/* ---- No user-serviceable parts below ---- */ - -static const char version[] = - "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; - -#include "lib8390.c" - -#define NE_BASE (dev->base_addr) -#define NE_CMD 0x00 -#define NE_DATAPORT (ei_status.word16?0x20:0x10) /* NatSemi-defined port window offset. */ -#define NE_RESET (ei_status.word16?0x3f:0x1f) /* Issue a read to reset, a write to clear. */ -#define NE_IO_EXTENT (ei_status.word16?0x40:0x20) - -#define NESM_START_PG 0x40 /* First page of TX buffer */ -#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ - -static int ne_probe1(struct net_device *dev, int ioaddr); - -static int ne_open(struct net_device *dev); -static int ne_close(struct net_device *dev); - -static void ne_reset_8390(struct net_device *dev); -static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void ne_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void ne_block_output(struct net_device *dev, const int count, - const unsigned char *buf, const int start_page); - - -static u32 reg_offset[16]; - -static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr) -{ - struct ei_device *ei_local = netdev_priv(dev); - int i; - unsigned char bus_width; - - bus_width = *(volatile unsigned char *)ABWCR; - bus_width &= 1 << ((base_addr >> 21) & 7); - - for (i = 0; i < ARRAY_SIZE(reg_offset); i++) - if (bus_width == 0) - reg_offset[i] = i * 2 + 1; - else - reg_offset[i] = i; - - ei_local->reg_offset = reg_offset; - return 0; -} - -static int __initdata h8300_ne_count = 0; -#ifdef CONFIG_H8300H_H8MAX -static unsigned long __initdata h8300_ne_base[] = { 0x800600 }; -static int h8300_ne_irq[] = {EXT_IRQ4}; -#endif -#ifdef CONFIG_H8300H_AKI3068NET -static unsigned long __initdata h8300_ne_base[] = { 0x200000 }; -static int h8300_ne_irq[] = {EXT_IRQ5}; -#endif - -static inline int init_dev(struct net_device *dev) -{ - if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) { - dev->base_addr = h8300_ne_base[h8300_ne_count]; - dev->irq = h8300_ne_irq[h8300_ne_count]; - h8300_ne_count++; - return 0; - } else - return -ENODEV; -} - -/* Probe for various non-shared-memory ethercards. - - NEx000-clone boards have a Station Address PROM (SAPROM) in the packet - buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of - the SAPROM, while other supposed NE2000 clones must be detected by their - SA prefix. - - Reading the SAPROM from a word-wide card with the 8390 set in byte-wide - mode results in doubled values, which can be detected and compensated for. - - The probe is also responsible for initializing the card and filling - in the 'dev' and 'ei_status' structures. - - We use the minimum memory size for some ethercard product lines, iff we can't - distinguish models. You can increase the packet buffer size by setting - PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: - E1010 starts at 0x100 and ends at 0x2000. - E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") - E2010 starts at 0x100 and ends at 0x4000. - E2010-x starts at 0x100 and ends at 0xffff. */ - -static int __init do_ne_probe(struct net_device *dev) -{ - unsigned int base_addr = dev->base_addr; - - /* First check any supplied i/o locations. User knows best. <cough> */ - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ne_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return -ENXIO; - - return -ENODEV; -} - -static void cleanup_card(struct net_device *dev) -{ - free_irq(dev->irq, dev); - release_region(dev->base_addr, NE_IO_EXTENT); -} - -#ifndef MODULE -struct net_device * __init ne_probe(int unit) -{ - struct net_device *dev = ____alloc_ei_netdev(0); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (init_dev(dev)) - return ERR_PTR(-ENODEV); - - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - - err = init_reg_offset(dev, dev->base_addr); - if (err) - goto out; - - err = do_ne_probe(dev); - if (err) - goto out; - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif - -static const struct net_device_ops ne_netdev_ops = { - .ndo_open = ne_open, - .ndo_stop = ne_close, - - .ndo_start_xmit = __ei_start_xmit, - .ndo_tx_timeout = __ei_tx_timeout, - .ndo_get_stats = __ei_get_stats, - .ndo_set_rx_mode = __ei_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_change_mtu = eth_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = __ei_poll, -#endif -}; - -static int __init ne_probe1(struct net_device *dev, int ioaddr) -{ - int i; - unsigned char SA_prom[16]; - int wordlength = 2; - const char *name = NULL; - int start_page, stop_page; - int reg0, ret; - static unsigned version_printed; - struct ei_device *ei_local = netdev_priv(dev); - unsigned char bus_width; - - if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) - return -EBUSY; - - reg0 = inb_p(ioaddr); - if (reg0 == 0xFF) { - ret = -ENODEV; - goto err_out; - } - - /* Do a preliminary verification that we have a 8390. */ - { - int regd; - outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); - regd = inb_p(ioaddr + EI_SHIFT(0x0d)); - outb_p(0xff, ioaddr + EI_SHIFT(0x0d)); - outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); - inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ - if (inb_p(ioaddr + EN0_COUNTER0) != 0) { - outb_p(reg0, ioaddr + EI_SHIFT(0)); - outb_p(regd, ioaddr + EI_SHIFT(0x0d)); /* Restore the old values. */ - ret = -ENODEV; - goto err_out; - } - } - - if (ei_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version1); - - printk(KERN_INFO "NE*000 ethercard probe at %08x:", ioaddr); - - /* Read the 16 bytes of station address PROM. - We must first initialize registers, similar to NS8390_init(eifdev, 0). - We can't reliably read the SAPROM address without this. - (I learned the hard way!). */ - { - struct {unsigned char value, offset; } program_seq[] = - { - {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ - {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ - {0x00, EN0_RCNTLO}, /* Clear the count regs. */ - {0x00, EN0_RCNTHI}, - {0x00, EN0_IMR}, /* Mask completion irq. */ - {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ - {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ - {32, EN0_RCNTLO}, - {0x00, EN0_RCNTHI}, - {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ - {0x00, EN0_RSARHI}, - {E8390_RREAD+E8390_START, E8390_CMD}, - }; - - for (i = 0; i < ARRAY_SIZE(program_seq); i++) - outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - - } - bus_width = *(volatile unsigned char *)ABWCR; - bus_width &= 1 << ((ioaddr >> 21) & 7); - ei_status.word16 = (bus_width == 0); /* temporary setting */ - for(i = 0; i < 16 /*sizeof(SA_prom)*/; i++) { - SA_prom[i] = inb_p(ioaddr + NE_DATAPORT); - inb_p(ioaddr + NE_DATAPORT); /* dummy read */ - } - - start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; - - if (bus_width) - wordlength = 1; - else - outb_p(0x49, ioaddr + EN0_DCFG); - - /* Set up the rest of the parameters. */ - name = (wordlength == 2) ? "NE2000" : "NE1000"; - - if (! dev->irq) { - printk(" failed to detect IRQ line.\n"); - ret = -EAGAIN; - goto err_out; - } - - /* Snarf the interrupt now. There's no point in waiting since we cannot - share and the board will usually be enabled. */ - ret = request_irq(dev->irq, __ei_interrupt, 0, name, dev); - if (ret) { - printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); - goto err_out; - } - - dev->base_addr = ioaddr; - - for (i = 0; i < ETH_ALEN; i++) - dev->dev_addr[i] = SA_prom[i]; - printk(" %pM\n", dev->dev_addr); - - printk("%s: %s found at %#x, using IRQ %d.\n", - dev->name, name, ioaddr, dev->irq); - - ei_status.name = name; - ei_status.tx_start_page = start_page; - ei_status.stop_page = stop_page; - ei_status.word16 = (wordlength == 2); - - ei_status.rx_start_page = start_page + TX_PAGES; -#ifdef PACKETBUF_MEMSIZE - /* Allow the packet buffer size to be overridden by know-it-alls. */ - ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; -#endif - - ei_status.reset_8390 = &ne_reset_8390; - ei_status.block_input = &ne_block_input; - ei_status.block_output = &ne_block_output; - ei_status.get_8390_hdr = &ne_get_8390_hdr; - ei_status.priv = 0; - - dev->netdev_ops = &ne_netdev_ops; - - __NS8390_init(dev, 0); - - ret = register_netdev(dev); - if (ret) - goto out_irq; - return 0; -out_irq: - free_irq(dev->irq, dev); -err_out: - release_region(ioaddr, NE_IO_EXTENT); - return ret; -} - -static int ne_open(struct net_device *dev) -{ - __ei_open(dev); - return 0; -} - -static int ne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); - __ei_close(dev); - return 0; -} - -/* Hard reset the card. This used to pause for the same period that a - 8390 reset command required, but that shouldn't be necessary. */ - -static void ne_reset_8390(struct net_device *dev) -{ - unsigned long reset_start_time = jiffies; - struct ei_device *ei_local = netdev_priv(dev); - - if (ei_debug > 1) - printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); - - /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ - outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); - - ei_status.txing = 0; - ei_status.dmaing = 0; - - /* This check _should_not_ be necessary, omit eventually. */ - while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (time_after(jiffies, reset_start_time + 2*HZ/100)) { - printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); - break; - } - outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ -} - -/* Grab the 8390 specific header. Similar to the block_input routine, but - we don't need to be concerned with ring wrap as the header will be at - the start of a page, so we optimize accordingly. */ - -static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - struct ei_device *ei_local = netdev_priv(dev); - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - - if (ei_status.dmaing) - { - printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); - return; - } - - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, NE_BASE + NE_CMD); - outb_p(sizeof(struct e8390_pkt_hdr), NE_BASE + EN0_RCNTLO); - outb_p(0, NE_BASE + EN0_RCNTHI); - outb_p(0, NE_BASE + EN0_RSARLO); /* On page boundary */ - outb_p(ring_page, NE_BASE + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); - - if (ei_status.word16) { - int len; - unsigned short *p = (unsigned short *)hdr; - for (len = sizeof(struct e8390_pkt_hdr)>>1; len > 0; len--) - *p++ = inw(NE_BASE + NE_DATAPORT); - } else - insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); - - outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; - - le16_to_cpus(&hdr->count); -} - -/* Block input and output, similar to the Crynwr packet driver. If you - are porting to a new ethercard, look at the packet driver source for hints. - The NEx000 doesn't share the on-board packet memory -- you have to put - the packet out through the "remote DMA" dataport using outb. */ - -static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - struct ei_device *ei_local = netdev_priv(dev); -#ifdef NE_SANITY_CHECK - int xfer_count = count; -#endif - char *buf = skb->data; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) - { - printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock); - return; - } - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, NE_BASE + NE_CMD); - outb_p(count & 0xff, NE_BASE + EN0_RCNTLO); - outb_p(count >> 8, NE_BASE + EN0_RCNTHI); - outb_p(ring_offset & 0xff, NE_BASE + EN0_RSARLO); - outb_p(ring_offset >> 8, NE_BASE + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); - if (ei_status.word16) - { - int len; - unsigned short *p = (unsigned short *)buf; - for (len = count>>1; len > 0; len--) - *p++ = inw(NE_BASE + NE_DATAPORT); - if (count & 0x01) - { - buf[count-1] = inb(NE_BASE + NE_DATAPORT); -#ifdef NE_SANITY_CHECK - xfer_count++; -#endif - } - } else { - insb(NE_BASE + NE_DATAPORT, buf, count); - } - -#ifdef NE_SANITY_CHECK - /* This was for the ALPHA version only, but enough people have - been encountering problems so it is still here. If you see - this message you either 1) have a slightly incompatible clone - or 2) have noise/speed problems with your bus. */ - - if (ei_debug > 1) - { - /* DMA termination address check... */ - int addr, tries = 20; - do { - /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here - -- it's broken for Rx on some cards! */ - int high = inb_p(NE_BASE + EN0_RSARHI); - int low = inb_p(NE_BASE + EN0_RSARLO); - addr = (high << 8) + low; - if (((ring_offset + xfer_count) & 0xff) == low) - break; - } while (--tries > 0); - if (tries <= 0) - printk(KERN_WARNING "%s: RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, ring_offset + xfer_count, addr); - } -#endif - outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; -} - -static void ne_block_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page) -{ - struct ei_device *ei_local = netdev_priv(dev); - unsigned long dma_start; -#ifdef NE_SANITY_CHECK - int retries = 0; -#endif - - /* Round the count up for word writes. Do we need to do this? - What effect will an odd byte count have on the 8390? - I should check someday. */ - - if (ei_status.word16 && (count & 0x01)) - count++; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) - { - printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d]\n", - dev->name, ei_status.dmaing, ei_status.irqlock); - return; - } - ei_status.dmaing |= 0x01; - /* We should already be in page 0, but to be safe... */ - outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, NE_BASE + NE_CMD); - -#ifdef NE_SANITY_CHECK -retry: -#endif - -#ifdef NE8390_RW_BUGFIX - /* Handle the read-before-write bug the same way as the - Crynwr packet driver -- the NatSemi method doesn't work. - Actually this doesn't always work either, but if you have - problems with your NEx000 this is better than nothing! */ - - outb_p(0x42, NE_BASE + EN0_RCNTLO); - outb_p(0x00, NE_BASE + EN0_RCNTHI); - outb_p(0x42, NE_BASE + EN0_RSARLO); - outb_p(0x00, NE_BASE + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, NE_BASE + NE_CMD); - /* Make certain that the dummy read has occurred. */ - udelay(6); -#endif - - outb_p(ENISR_RDC, NE_BASE + EN0_ISR); - - /* Now the normal output. */ - outb_p(count & 0xff, NE_BASE + EN0_RCNTLO); - outb_p(count >> 8, NE_BASE + EN0_RCNTHI); - outb_p(0x00, NE_BASE + EN0_RSARLO); - outb_p(start_page, NE_BASE + EN0_RSARHI); - - outb_p(E8390_RWRITE+E8390_START, NE_BASE + NE_CMD); - if (ei_status.word16) { - int len; - unsigned short *p = (unsigned short *)buf; - for (len = count>>1; len > 0; len--) - outw(*p++, NE_BASE + NE_DATAPORT); - } else { - outsb(NE_BASE + NE_DATAPORT, buf, count); - } - - dma_start = jiffies; - -#ifdef NE_SANITY_CHECK - /* This was for the ALPHA version only, but enough people have - been encountering problems so it is still here. */ - - if (ei_debug > 1) - { - /* DMA termination address check... */ - int addr, tries = 20; - do { - int high = inb_p(NE_BASE + EN0_RSARHI); - int low = inb_p(NE_BASE + EN0_RSARLO); - addr = (high << 8) + low; - if ((start_page << 8) + count == addr) - break; - } while (--tries > 0); - - if (tries <= 0) - { - printk(KERN_WARNING "%s: Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, (start_page << 8) + count, addr); - if (retries++ == 0) - goto retry; - } - } -#endif - - while ((inb_p(NE_BASE + EN0_ISR) & ENISR_RDC) == 0) - if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ - printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); - ne_reset_8390(dev); - __NS8390_init(dev,1); - break; - } - - outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; -} - - -#ifdef MODULE -#define MAX_NE_CARDS 1 /* Max number of NE cards per module */ -static struct net_device *dev_ne[MAX_NE_CARDS]; -static int io[MAX_NE_CARDS]; -static int irq[MAX_NE_CARDS]; -static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ - -module_param_array(io, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -module_param_array(bad, int, NULL, 0); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s)"); -MODULE_DESCRIPTION("H8/300 NE2000 Ethernet driver"); -MODULE_LICENSE("GPL"); - -/* This is set up so that no ISA autoprobe takes place. We can't guarantee -that the ne2k probe is the last 8390 based probe to take place (as it -is at boot) and so the probe will get confused by any other 8390 cards. -ISA device autoprobes on a running machine are not recommended anyway. */ - -int init_module(void) -{ - int this_dev, found = 0; - int err; - - for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = ____alloc_ei_netdev(0); - if (!dev) - break; - if (io[this_dev]) { - dev->irq = irq[this_dev]; - dev->mem_end = bad[this_dev]; - dev->base_addr = io[this_dev]; - } else { - dev->base_addr = h8300_ne_base[this_dev]; - dev->irq = h8300_ne_irq[this_dev]; - } - err = init_reg_offset(dev, dev->base_addr); - if (!err) { - if (do_ne_probe(dev) == 0) { - dev_ne[found++] = dev; - continue; - } - } - free_netdev(dev); - if (found) - break; - if (io[this_dev] != 0) - printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", dev->base_addr); - else - printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); - return -ENXIO; - } - if (found) - return 0; - return -ENODEV; -} - -void cleanup_module(void) -{ - int this_dev; - - for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = dev_ne[this_dev]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -#endif /* MODULE */ diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index 9e160148726..d0878526c0c 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -628,12 +628,12 @@ static const struct net_device_ops arc_emac_netdev_ops = { static int arc_emac_probe(struct platform_device *pdev) { - struct resource res_regs, res_irq; + struct resource res_regs; struct device_node *phy_node; struct arc_emac_priv *priv; struct net_device *ndev; const char *mac_addr; - unsigned int id, clock_frequency; + unsigned int id, clock_frequency, irq; int err; if (!pdev->dev.of_node) @@ -661,8 +661,8 @@ static int arc_emac_probe(struct platform_device *pdev) } /* Get IRQ from device tree */ - err = of_irq_to_resource(pdev->dev.of_node, 0, &res_irq); - if (!err) { + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) { dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n"); return -ENODEV; } @@ -711,7 +711,7 @@ static int arc_emac_probe(struct platform_device *pdev) goto out; } - ndev->irq = res_irq.start; + ndev->irq = irq; dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq); /* Register interrupt handler for device */ diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 7583a9572bc..f8b92864fc5 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -32,7 +32,9 @@ #include <linux/fs.h> #include <linux/platform_device.h> #include <linux/phy.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/gfp.h> #include <asm/immap_cpm2.h> @@ -88,7 +90,7 @@ static int do_pd_setup(struct fs_enet_private *fep) struct fs_platform_info *fpi = fep->fpi; int ret = -EINVAL; - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) goto out; diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c index 9ae6cdbcac2..a9a00f39521 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c @@ -31,7 +31,9 @@ #include <linux/bitops.h> #include <linux/fs.h> #include <linux/platform_device.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/gfp.h> #include <asm/irq.h> @@ -98,7 +100,7 @@ static int do_pd_setup(struct fs_enet_private *fep) { struct platform_device *ofdev = to_platform_device(fep->dev); - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) return -EINVAL; diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c index 22a02a76706..d37cd4ebac6 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c @@ -31,6 +31,8 @@ #include <linux/bitops.h> #include <linux/fs.h> #include <linux/platform_device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/irq.h> @@ -98,7 +100,7 @@ static int do_pd_setup(struct fs_enet_private *fep) { struct platform_device *ofdev = to_platform_device(fep->dev); - fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); + fep->interrupt = irq_of_parse_and_map(ofdev->dev.of_node, 0); if (fep->interrupt == NO_IRQ) return -EINVAL; diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c index 844ecfa84d1..67caaacd19e 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c @@ -22,6 +22,7 @@ #include <linux/mii.h> #include <linux/platform_device.h> #include <linux/mdio-bitbang.h> +#include <linux/of_address.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c index 2f1c46a12f0..ac5d447ff8c 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c @@ -31,6 +31,7 @@ #include <linux/ethtool.h> #include <linux/bitops.h> #include <linux/platform_device.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <asm/pgtable.h> diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 9fbe4dda7a0..ef95c3ae53e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -78,6 +78,8 @@ #include <linux/if_vlan.h> #include <linux/spinlock.h> #include <linux/mm.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> #include <linux/ip.h> diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 5930c39672d..64b329fecf3 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -31,6 +31,8 @@ #include <linux/mii.h> #include <linux/phy.h> #include <linux/workqueue.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/of_net.h> #include <linux/of_platform.h> diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index c1b6e7e31aa..d449fcb9019 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/phy.h> #include <linux/mdio.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of_mdio.h> diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 6b5c7222342..cdf2321f1f0 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -39,6 +39,8 @@ #include <linux/bitops.h> #include <linux/workqueue.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_net.h> #include <linux/slab.h> diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c index e7847510eda..9d75fef6396 100644 --- a/drivers/net/ethernet/ibm/emac/mal.c +++ b/drivers/net/ethernet/ibm/emac/mal.c @@ -27,6 +27,7 @@ #include <linux/delay.h> #include <linux/slab.h> +#include <linux/of_irq.h> #include "core.h" #include <asm/dcr-regs.h> diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c index c47e23d6eea..4fb2f96da23 100644 --- a/drivers/net/ethernet/ibm/emac/rgmii.c +++ b/drivers/net/ethernet/ibm/emac/rgmii.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/ethtool.h> +#include <linux/of_address.h> #include <asm/io.h> #include "emac.h" diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c index c231a4a32c4..9f24769ed82 100644 --- a/drivers/net/ethernet/ibm/emac/tah.c +++ b/drivers/net/ethernet/ibm/emac/tah.c @@ -18,6 +18,7 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ +#include <linux/of_address.h> #include <asm/io.h> #include "emac.h" diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c index 4cdf286f7ee..9ca67a38c06 100644 --- a/drivers/net/ethernet/ibm/emac/zmii.c +++ b/drivers/net/ethernet/ibm/emac/zmii.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/ethtool.h> +#include <linux/of_address.h> #include <asm/io.h> #include "emac.h" diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c index e85c2e7e824..afd9873e9bd 100644 --- a/drivers/net/ethernet/smsc/smc9194.c +++ b/drivers/net/ethernet/smsc/smc9194.c @@ -95,14 +95,6 @@ static const char version[] = #define USE_32_BIT 1 #endif -#if defined(__H8300H__) || defined(__H8300S__) -#define NO_AUTOPROBE -#undef insl -#undef outsl -#define insl(a,b,l) io_insl_noswap(a,b,l) -#define outsl(a,b,l) io_outsl_noswap(a,b,l) -#endif - /* .the SMC9194 can be at any of the following port addresses. To change, .for a slightly different card, you can add it to the array. Keep in @@ -114,12 +106,6 @@ struct devlist { unsigned int irq; }; -#if defined(CONFIG_H8S_EDOSK2674) -static struct devlist smc_devlist[] __initdata = { - {.port = 0xf80000, .irq = 16}, - {.port = 0, .irq = 0 }, -}; -#else static struct devlist smc_devlist[] __initdata = { {.port = 0x200, .irq = 0}, {.port = 0x220, .irq = 0}, @@ -139,7 +125,6 @@ static struct devlist smc_devlist[] __initdata = { {.port = 0x3E0, .irq = 0}, {.port = 0, .irq = 0}, }; -#endif /* . Wait time for memory to be free. This probably shouldn't be . tuned that much, as waiting for this means nothing else happens @@ -651,11 +636,7 @@ static void smc_hardware_send_packet( struct net_device * dev ) #ifdef USE_32_BIT if ( length & 0x2 ) { outsl(ioaddr + DATA_1, buf, length >> 2 ); -#if !defined(__H8300H__) && !defined(__H8300S__) outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); -#else - ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); -#endif } else outsl(ioaddr + DATA_1, buf, length >> 2 ); @@ -899,7 +880,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) retval = -ENODEV; goto err_out; } -#if !defined(CONFIG_H8S_EDOSK2674) /* well, we've already written once, so hopefully another time won't hurt. This time, I need to switch the bank register to bank 1, so I can access the base address register */ @@ -914,10 +894,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) retval = -ENODEV; goto err_out; } -#else - (void)base_address_register; /* Warning suppression */ -#endif - /* check if the revision register is something that I recognize. These might need to be added to later, as future revisions diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 0029148077a..1f236412632 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -36,6 +36,7 @@ #include <linux/netdevice.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> #include <linux/of_address.h> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 78cc7605332..de6f8990246 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -17,6 +17,7 @@ config PROC_DEVICETREE config OF_SELFTEST bool "Device Tree Runtime self tests" + depends on OF_IRQ help This option builds in test cases for the device tree infrastructure that are executed one at boot time, and the results dumped to the diff --git a/drivers/of/address.c b/drivers/of/address.c index b55c2189076..4b9317bdb81 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -489,7 +489,7 @@ static u64 __of_translate_address(struct device_node *dev, int na, ns, pna, pns; u64 result = OF_BAD_ADDR; - pr_debug("OF: ** translation for device %s **\n", dev->full_name); + pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev)); /* Increase refcount at current level */ of_node_get(dev); @@ -504,13 +504,13 @@ static u64 __of_translate_address(struct device_node *dev, bus->count_cells(dev, &na, &ns); if (!OF_CHECK_COUNTS(na, ns)) { printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); + of_node_full_name(dev)); goto bail; } memcpy(addr, in_addr, na * 4); pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", - bus->name, na, ns, parent->full_name); + bus->name, na, ns, of_node_full_name(parent)); of_dump_addr("OF: translating address:", addr, na); /* Translate */ @@ -532,12 +532,12 @@ static u64 __of_translate_address(struct device_node *dev, pbus->count_cells(dev, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) { printk(KERN_ERR "prom_parse: Bad cell count for %s\n", - dev->full_name); + of_node_full_name(dev)); break; } pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", - pbus->name, pna, pns, parent->full_name); + pbus->name, pna, pns, of_node_full_name(parent)); /* Apply bus translation */ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) @@ -626,6 +626,14 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, } EXPORT_SYMBOL(of_get_address); +unsigned long __weak pci_address_to_pio(phys_addr_t address) +{ + if (address > IO_SPACE_LIMIT) + return (unsigned long)-1; + + return (unsigned long) address; +} + static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, const char *name, struct resource *r) diff --git a/drivers/of/base.c b/drivers/of/base.c index 7d4c70f859e..f807d0edabf 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -74,6 +74,13 @@ int of_n_size_cells(struct device_node *np) } EXPORT_SYMBOL(of_n_size_cells); +#ifdef CONFIG_NUMA +int __weak of_node_to_nid(struct device_node *np) +{ + return numa_node_id(); +} +#endif + #if defined(CONFIG_OF_DYNAMIC) /** * of_node_get - Increment refcount of a node @@ -265,9 +272,9 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, ac = of_n_addr_cells(cpun); cell = of_get_property(cpun, prop_name, &prop_len); - if (!cell) + if (!cell || !ac) return false; - prop_len /= sizeof(*cell); + prop_len /= sizeof(*cell) * ac; for (tid = 0; tid < prop_len; tid++) { hwid = of_read_number(cell, ac); if (arch_match_cpu_phys_id(cpu, hwid)) { @@ -280,6 +287,31 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, return false; } +/* + * arch_find_n_match_cpu_physical_id - See if the given device node is + * for the cpu corresponding to logical cpu 'cpu'. Return true if so, + * else false. If 'thread' is non-NULL, the local thread number within the + * core is returned in it. + */ +bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, + int cpu, unsigned int *thread) +{ + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. + */ + if (IS_ENABLED(CONFIG_PPC) && + __of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", + cpu, thread)) + return true; + + if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + return true; + + return false; +} + /** * of_get_cpu_node - Get device node associated with the given logical CPU * @@ -300,24 +332,10 @@ static bool __of_find_n_match_cpu_property(struct device_node *cpun, */ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) { - struct device_node *cpun, *cpus; + struct device_node *cpun; - cpus = of_find_node_by_path("/cpus"); - if (!cpus) - return NULL; - - for_each_child_of_node(cpus, cpun) { - if (of_node_cmp(cpun->type, "cpu")) - continue; - /* Check for non-standard "ibm,ppc-interrupt-server#s" property - * for thread ids on PowerPC. If it doesn't exist fallback to - * standard "reg" property. - */ - if (IS_ENABLED(CONFIG_PPC) && - __of_find_n_match_cpu_property(cpun, - "ibm,ppc-interrupt-server#s", cpu, thread)) - return cpun; - if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) + for_each_node_by_type(cpun, "cpu") { + if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) return cpun; } return NULL; @@ -1174,6 +1192,15 @@ int of_property_count_strings(struct device_node *np, const char *propname) } EXPORT_SYMBOL_GPL(of_property_count_strings); +void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) +{ + int i; + printk("%s %s", msg, of_node_full_name(args->np)); + for (i = 0; i < args->args_count; i++) + printk(i ? ",%08x" : ":%08x", args->args[i]); + printk("\n"); +} + static int __of_parse_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name, @@ -1882,3 +1909,34 @@ int of_device_is_stdout_path(struct device_node *dn) return of_stdout == dn; } EXPORT_SYMBOL_GPL(of_device_is_stdout_path); + +/** + * of_find_next_cache_node - Find a node's subsidiary cache + * @np: node of type "cpu" or "cache" + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. Caller should hold a reference + * to np. + */ +struct device_node *of_find_next_cache_node(const struct device_node *np) +{ + struct device_node *child; + const phandle *handle; + + handle = of_get_property(np, "l2-cache", NULL); + if (!handle) + handle = of_get_property(np, "next-level-cache", NULL); + + if (handle) + return of_find_node_by_phandle(be32_to_cpup(handle)); + + /* OF on pmac has nodes instead of properties named "l2-cache" + * beneath CPU nodes. + */ + if (!strcmp(np->type, "cpu")) + for_each_child_of_node(np, child) + if (!strcmp(child->type, "cache")) + return child; + + return NULL; +} diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index a4fa9ad31b8..2fa024b97c4 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -618,12 +618,72 @@ int __init of_scan_flat_dt_by_path(const char *path, return ret; } +const char * __init of_flat_dt_get_machine_name(void) +{ + const char *name; + unsigned long dt_root = of_get_flat_dt_root(); + + name = of_get_flat_dt_prop(dt_root, "model", NULL); + if (!name) + name = of_get_flat_dt_prop(dt_root, "compatible", NULL); + return name; +} + +/** + * of_flat_dt_match_machine - Iterate match tables to find matching machine. + * + * @default_match: A machine specific ptr to return in case of no match. + * @get_next_compat: callback function to return next compatible match table. + * + * Iterate through machine match tables to find the best match for the machine + * compatible string in the FDT. + */ +const void * __init of_flat_dt_match_machine(const void *default_match, + const void * (*get_next_compat)(const char * const**)) +{ + const void *data = NULL; + const void *best_data = default_match; + const char *const *compat; + unsigned long dt_root; + unsigned int best_score = ~1, score = 0; + + dt_root = of_get_flat_dt_root(); + while ((data = get_next_compat(&compat))) { + score = of_flat_dt_match(dt_root, compat); + if (score > 0 && score < best_score) { + best_data = data; + best_score = score; + } + } + if (!best_data) { + const char *prop; + long size; + + pr_err("\n unrecognized device tree list:\n[ "); + + prop = of_get_flat_dt_prop(dt_root, "compatible", &size); + if (prop) { + while (size > 0) { + printk("'%s' ", prop); + size -= strlen(prop) + 1; + prop += strlen(prop) + 1; + } + } + printk("]\n\n"); + return NULL; + } + + pr_info("Machine model: %s\n", of_flat_dt_get_machine_name()); + + return best_data; +} + #ifdef CONFIG_BLK_DEV_INITRD /** * early_init_dt_check_for_initrd - Decode initrd location from flat tree * @node: reference to node containing initrd location ('chosen') */ -void __init early_init_dt_check_for_initrd(unsigned long node) +static void __init early_init_dt_check_for_initrd(unsigned long node) { u64 start, end; unsigned long len; @@ -641,12 +701,15 @@ void __init early_init_dt_check_for_initrd(unsigned long node) return; end = of_read_number(prop, len/4); - early_init_dt_setup_initrd_arch(start, end); + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; + pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", (unsigned long long)start, (unsigned long long)end); } #else -inline void early_init_dt_check_for_initrd(unsigned long node) +static inline void early_init_dt_check_for_initrd(unsigned long node) { } #endif /* CONFIG_BLK_DEV_INITRD */ @@ -774,6 +837,25 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, } #ifdef CONFIG_HAVE_MEMBLOCK +void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) +{ + const u64 phys_offset = __pa(PAGE_OFFSET); + base &= PAGE_MASK; + size &= PAGE_MASK; + if (base + size < phys_offset) { + pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", + base, base + size); + return; + } + if (base < phys_offset) { + pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", + base, phys_offset); + size -= phys_offset - base; + base = phys_offset; + } + memblock_add(base, size); +} + /* * called from unflatten_device_tree() to bootstrap devicetree itself * Architectures can override this definition if memblock isn't used @@ -784,6 +866,32 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align) } #endif +bool __init early_init_dt_scan(void *params) +{ + if (!params) + return false; + + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* check device tree validity */ + if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) { + initial_boot_params = NULL; + return false; + } + + /* Retrieve various information from the /chosen node */ + of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); + + /* Initialize {size,address}-cells info */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + + /* Setup memory, calling early_init_dt_add_memory_arch */ + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + + return true; +} + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -801,4 +909,28 @@ void __init unflatten_device_tree(void) of_alias_scan(early_init_dt_alloc_memory_arch); } +/** + * unflatten_and_copy_device_tree - copy and create tree of device_nodes from flat blob + * + * Copies and unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. This should only be used when the FDT memory has not been + * reserved such is the case when the FDT is built-in to the kernel init + * section. If the FDT memory is reserved already then unflatten_device_tree + * should be used instead. + */ +void __init unflatten_and_copy_device_tree(void) +{ + int size = __be32_to_cpu(initial_boot_params->totalsize); + void *dt = early_init_dt_alloc_memory_arch(size, + __alignof__(struct boot_param_header)); + + if (dt) { + memcpy(dt, initial_boot_params, size); + initial_boot_params = dt; + } + unflatten_device_tree(); +} + #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 1752988d6aa..786b0b47fae 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -31,18 +31,17 @@ * @dev: Device node of the device whose interrupt is to be mapped * @index: Index of the interrupt to map * - * This function is a wrapper that chains of_irq_map_one() and + * This function is a wrapper that chains of_irq_parse_one() and * irq_create_of_mapping() to make things easier to callers */ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) { - struct of_irq oirq; + struct of_phandle_args oirq; - if (of_irq_map_one(dev, index, &oirq)) + if (of_irq_parse_one(dev, index, &oirq)) return 0; - return irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); + return irq_create_of_mapping(&oirq); } EXPORT_SYMBOL_GPL(irq_of_parse_and_map); @@ -79,33 +78,34 @@ struct device_node *of_irq_find_parent(struct device_node *child) } /** - * of_irq_map_raw - Low level interrupt tree parsing + * of_irq_parse_raw - Low level interrupt tree parsing * @parent: the device interrupt parent - * @intspec: interrupt specifier ("interrupts" property of the device) - * @ointsize: size of the passed in interrupt specifier - * @addr: address specifier (start of "reg" property of the device) - * @out_irq: structure of_irq filled by this function + * @addr: address specifier (start of "reg" property of the device) in be32 format + * @out_irq: structure of_irq updated by this function * * Returns 0 on success and a negative number on error * * This function is a low-level interrupt tree walking function. It * can be used to do a partial walk with synthetized reg and interrupts * properties, for example when resolving PCI interrupts when no device - * node exist for the parent. + * node exist for the parent. It takes an interrupt specifier structure as + * input, walks the tree looking for any interrupt-map properties, translates + * the specifier for each map, and then returns the translated map. */ -int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, - u32 ointsize, const __be32 *addr, struct of_irq *out_irq) +int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq) { struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; - const __be32 *tmp, *imap, *imask; + __be32 initial_match_array[MAX_PHANDLE_ARGS]; + const __be32 *match_array = initial_match_array; + const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 }; u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; int imaplen, match, i; - pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", - parent->full_name, be32_to_cpup(intspec), - be32_to_cpup(intspec + 1), ointsize); +#ifdef DEBUG + of_print_phandle_args("of_irq_parse_raw: ", out_irq); +#endif - ipar = of_node_get(parent); + ipar = of_node_get(out_irq->np); /* First get the #interrupt-cells property of the current cursor * that tells us how to interpret the passed-in intspec. If there @@ -126,9 +126,9 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, goto fail; } - pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize); - if (ointsize != intsize) + if (out_irq->args_count != intsize) return -EINVAL; /* Look for this #address-cells. We have to implement the old linux @@ -147,6 +147,16 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, pr_debug(" -> addrsize=%d\n", addrsize); + /* Range check so that the temporary buffer doesn't overflow */ + if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) + goto fail; + + /* Precalculate the match array - this simplifies match loop */ + for (i = 0; i < addrsize; i++) + initial_match_array[i] = addr ? addr[i] : 0; + for (i = 0; i < intsize; i++) + initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]); + /* Now start the actual "proper" walk of the interrupt tree */ while (ipar != NULL) { /* Now check if cursor is an interrupt-controller and if it is @@ -155,15 +165,19 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, if (of_get_property(ipar, "interrupt-controller", NULL) != NULL) { pr_debug(" -> got it !\n"); - for (i = 0; i < intsize; i++) - out_irq->specifier[i] = - of_read_number(intspec +i, 1); - out_irq->size = intsize; - out_irq->controller = ipar; of_node_put(old); return 0; } + /* + * interrupt-map parsing does not work without a reg + * property when #address-cells != 0 + */ + if (addrsize && !addr) { + pr_debug(" -> no reg passed in when needed !\n"); + goto fail; + } + /* Now look for an interrupt-map */ imap = of_get_property(ipar, "interrupt-map", &imaplen); /* No interrupt map, check for an interrupt parent */ @@ -176,34 +190,16 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, /* Look for a mask */ imask = of_get_property(ipar, "interrupt-map-mask", NULL); - - /* If we were passed no "reg" property and we attempt to parse - * an interrupt-map, then #address-cells must be 0. - * Fail if it's not. - */ - if (addr == NULL && addrsize != 0) { - pr_debug(" -> no reg passed in when needed !\n"); - goto fail; - } + if (!imask) + imask = dummy_imask; /* Parse interrupt-map */ match = 0; while (imaplen > (addrsize + intsize + 1) && !match) { /* Compare specifiers */ match = 1; - for (i = 0; i < addrsize && match; ++i) { - __be32 mask = imask ? imask[i] - : cpu_to_be32(0xffffffffu); - match = ((addr[i] ^ imap[i]) & mask) == 0; - } - for (; i < (addrsize + intsize) && match; ++i) { - __be32 mask = imask ? imask[i] - : cpu_to_be32(0xffffffffu); - match = - ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; - } - imap += addrsize + intsize; - imaplen -= addrsize + intsize; + for (i = 0; i < (addrsize + intsize); i++, imaplen--) + match &= !((match_array[i] ^ *imap++) & imask[i]); pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); @@ -237,6 +233,8 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, newintsize, newaddrsize); /* Check for malformed properties */ + if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)) + goto fail; if (imaplen < (newaddrsize + newintsize)) goto fail; @@ -248,12 +246,18 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, if (!match) goto fail; - of_node_put(old); - old = of_node_get(newpar); + /* + * Successfully parsed an interrrupt-map translation; copy new + * interrupt specifier into the out_irq structure + */ + of_node_put(out_irq->np); + out_irq->np = of_node_get(newpar); + + match_array = imap - newaddrsize - newintsize; + for (i = 0; i < newintsize; i++) + out_irq->args[i] = be32_to_cpup(imap - newintsize + i); + out_irq->args_count = intsize = newintsize; addrsize = newaddrsize; - intsize = newintsize; - intspec = imap - intsize; - addr = intspec - addrsize; skiplevel: /* Iterate again with new parent */ @@ -264,46 +268,53 @@ int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, } fail: of_node_put(ipar); - of_node_put(old); + of_node_put(out_irq->np); of_node_put(newpar); return -EINVAL; } -EXPORT_SYMBOL_GPL(of_irq_map_raw); +EXPORT_SYMBOL_GPL(of_irq_parse_raw); /** - * of_irq_map_one - Resolve an interrupt for a device + * of_irq_parse_one - Resolve an interrupt for a device * @device: the device whose interrupt is to be resolved * @index: index of the interrupt to resolve * @out_irq: structure of_irq filled by this function * - * This function resolves an interrupt, walking the tree, for a given - * device-tree node. It's the high level pendant to of_irq_map_raw(). + * This function resolves an interrupt for a node by walking the interrupt tree, + * finding which interrupt controller node it is attached to, and returning the + * interrupt specifier that can be used to retrieve a Linux IRQ number. */ -int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) +int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq) { struct device_node *p; const __be32 *intspec, *tmp, *addr; u32 intsize, intlen; - int res = -EINVAL; + int i, res = -EINVAL; - pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); + pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index); /* OldWorld mac stuff is "special", handle out of line */ if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) - return of_irq_map_oldworld(device, index, out_irq); + return of_irq_parse_oldworld(device, index, out_irq); + + /* Get the reg property (if any) */ + addr = of_get_property(device, "reg", NULL); /* Get the interrupts property */ intspec = of_get_property(device, "interrupts", &intlen); - if (intspec == NULL) - return -EINVAL; + if (intspec == NULL) { + /* Try the new-style interrupts-extended */ + res = of_parse_phandle_with_args(device, "interrupts-extended", + "#interrupt-cells", index, out_irq); + if (res) + return -EINVAL; + return of_irq_parse_raw(addr, out_irq); + } intlen /= sizeof(*intspec); pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); - /* Get the reg property (if any) */ - addr = of_get_property(device, "reg", NULL); - /* Look for the interrupt parent. */ p = of_irq_find_parent(device); if (p == NULL) @@ -321,14 +332,20 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq if ((index + 1) * intsize > intlen) goto out; - /* Get new specifier and map it */ - res = of_irq_map_raw(p, intspec + index * intsize, intsize, - addr, out_irq); + /* Copy intspec into irq structure */ + intspec += index * intsize; + out_irq->np = p; + out_irq->args_count = intsize; + for (i = 0; i < intsize; i++) + out_irq->args[i] = be32_to_cpup(intspec++); + + /* Check if there are any interrupt-map translations to process */ + res = of_irq_parse_raw(addr, out_irq); out: of_node_put(p); return res; } -EXPORT_SYMBOL_GPL(of_irq_map_one); +EXPORT_SYMBOL_GPL(of_irq_parse_one); /** * of_irq_to_resource - Decode a node's IRQ and return it as a resource @@ -354,8 +371,8 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) &name); r->start = r->end = irq; - r->flags = IORESOURCE_IRQ; - r->name = name ? name : dev->full_name; + r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq)); + r->name = name ? name : of_node_full_name(dev); } return irq; @@ -368,9 +385,10 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource); */ int of_irq_count(struct device_node *dev) { + struct of_phandle_args irq; int nr = 0; - while (of_irq_to_resource(dev, nr, NULL)) + while (of_irq_parse_one(dev, nr, &irq) == 0) nr++; return nr; diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index e5ca00893c0..84819963379 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -2,7 +2,6 @@ #include <linux/export.h> #include <linux/of.h> #include <linux/of_pci.h> -#include <asm/prom.h> static inline int __of_pci_pci_compare(struct device_node *node, unsigned int data) diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c index 67705381321..8736bc7676c 100644 --- a/drivers/of/of_pci_irq.c +++ b/drivers/of/of_pci_irq.c @@ -2,10 +2,9 @@ #include <linux/of_pci.h> #include <linux/of_irq.h> #include <linux/export.h> -#include <asm/prom.h> /** - * of_irq_map_pci - Resolve the interrupt for a PCI device + * of_irq_parse_pci - Resolve the interrupt for a PCI device * @pdev: the device whose interrupt is to be resolved * @out_irq: structure of_irq filled by this function * @@ -15,7 +14,7 @@ * PCI tree until an device-node is found, at which point it will finish * resolving using the OF tree walking. */ -int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) +int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) { struct device_node *dn, *ppnode; struct pci_dev *ppdev; @@ -30,7 +29,7 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) */ dn = pci_device_to_OF_node(pdev); if (dn) { - rc = of_irq_map_one(dn, 0, out_irq); + rc = of_irq_parse_one(dn, 0, out_irq); if (!rc) return rc; } @@ -85,9 +84,37 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) pdev = ppdev; } + out_irq->np = ppnode; + out_irq->args_count = 1; + out_irq->args[0] = lspec; lspec_be = cpu_to_be32(lspec); laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8)); - laddr[1] = laddr[2] = cpu_to_be32(0); - return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq); + laddr[1] = laddr[2] = cpu_to_be32(0); + return of_irq_parse_raw(laddr, out_irq); } -EXPORT_SYMBOL_GPL(of_irq_map_pci); +EXPORT_SYMBOL_GPL(of_irq_parse_pci); + +/** + * of_irq_parse_and_map_pci() - Decode a PCI irq from the device tree and map to a virq + * @dev: The pci device needing an irq + * @slot: PCI slot number; passed when used as map_irq callback. Unused + * @pin: PCI irq pin number; passed when used as map_irq callback. Unused + * + * @slot and @pin are unused, but included in the function so that this + * function can be used directly as the map_irq callback to pci_fixup_irqs(). + */ +int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin) +{ + struct of_phandle_args oirq; + int ret; + + ret = of_irq_parse_pci(dev, &oirq); + if (ret) { + dev_err(&dev->dev, "of_irq_parse_pci() failed with rc=%d\n", ret); + return 0; /* Proper return code 0 == NO_IRQ */ + } + + return irq_create_of_mapping(&oirq); +} +EXPORT_SYMBOL_GPL(of_irq_parse_and_map_pci); + diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 4ec19cbee57..7b666736c16 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -22,7 +22,6 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_pdt.h> -#include <asm/prom.h> static struct of_pdt_ops *of_pdt_prom_ops __initdata; diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f6dcde22082..fce088e6f54 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -215,6 +215,8 @@ static struct platform_device *of_platform_device_create_pdata( dev->archdata.dma_mask = 0xffffffffUL; #endif dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 0eb5c38b4e0..e21012bde63 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -9,18 +9,24 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/device.h> -static bool selftest_passed = true; +static struct selftest_results { + int passed; + int failed; +} selftest_results; + #define selftest(result, fmt, ...) { \ if (!(result)) { \ - pr_err("FAIL %s:%i " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ - selftest_passed = false; \ + selftest_results.failed++; \ + pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \ } else { \ - pr_info("pass %s:%i\n", __FILE__, __LINE__); \ + selftest_results.passed++; \ + pr_debug("pass %s():%i\n", __func__, __LINE__); \ } \ } @@ -131,7 +137,6 @@ static void __init of_selftest_property_match_string(void) struct device_node *np; int rc; - pr_info("start\n"); np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); if (!np) { pr_err("No testcase data in device tree\n"); @@ -154,6 +159,147 @@ static void __init of_selftest_property_match_string(void) selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); } +static void __init of_selftest_parse_interrupts(void) +{ + struct device_node *np; + struct of_phandle_args args; + int i, rc; + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 4; i++) { + bool passed = true; + args.args_count = 0; + rc = of_irq_parse_one(np, i, &args); + + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == (i + 1)); + + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts1"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 4; i++) { + bool passed = true; + args.args_count = 0; + rc = of_irq_parse_one(np, i, &args); + + /* Test the values from tests-phandle.dtsi */ + switch (i) { + case 0: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 9); + break; + case 1: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 10); + passed &= (args.args[1] == 11); + passed &= (args.args[2] == 12); + break; + case 2: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 13); + passed &= (args.args[1] == 14); + break; + case 3: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 15); + passed &= (args.args[1] == 16); + break; + default: + passed = false; + } + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); +} + +static void __init of_selftest_parse_interrupts_extended(void) +{ + struct device_node *np; + struct of_phandle_args args; + int i, rc; + + np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + for (i = 0; i < 7; i++) { + bool passed = true; + rc = of_irq_parse_one(np, i, &args); + + /* Test the values from tests-phandle.dtsi */ + switch (i) { + case 0: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 1); + break; + case 1: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 2); + passed &= (args.args[1] == 3); + passed &= (args.args[2] == 4); + break; + case 2: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 5); + passed &= (args.args[1] == 6); + break; + case 3: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 9); + break; + case 4: + passed &= !rc; + passed &= (args.args_count == 3); + passed &= (args.args[0] == 10); + passed &= (args.args[1] == 11); + passed &= (args.args[2] == 12); + break; + case 5: + passed &= !rc; + passed &= (args.args_count == 2); + passed &= (args.args[0] == 13); + passed &= (args.args[1] == 14); + break; + case 6: + passed &= !rc; + passed &= (args.args_count == 1); + passed &= (args.args[0] == 15); + break; + default: + passed = false; + } + + selftest(passed, "index %i - data error on node %s rc=%i\n", + i, args.np->full_name, rc); + } + of_node_put(np); +} + static int __init of_selftest(void) { struct device_node *np; @@ -168,7 +314,10 @@ static int __init of_selftest(void) pr_info("start of selftest - you will see error messages\n"); of_selftest_parse_phandle_with_args(); of_selftest_property_match_string(); - pr_info("end of selftest - %s\n", selftest_passed ? "PASS" : "FAIL"); + of_selftest_parse_interrupts(); + of_selftest_parse_interrupts_extended(); + pr_info("end of selftest - %i passed, %i failed\n", + selftest_results.passed, selftest_results.failed); return 0; } late_initcall(of_selftest); diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 70694ce38be..dc82ef096f3 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -37,7 +37,7 @@ config PARPORT_PC tristate "PC-style hardware" depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \ (!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \ - !XTENSA && !CRIS && !H8300 + !XTENSA && !CRIS ---help--- You should say Y here if you have a PC-style parallel port. All diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 80b2250ea19..c269e430c76 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -665,19 +665,6 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) return 1; } -static int mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - struct of_irq oirq; - int ret; - - ret = of_irq_map_pci(dev, &oirq); - if (ret) - return ret; - - return irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); -} - static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) { struct mvebu_pcie *pcie = sys_to_pcie(sys); @@ -732,7 +719,7 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie) hw.private_data = (void **)&pcie; hw.setup = mvebu_pcie_setup; hw.scan = mvebu_pcie_scan_bus; - hw.map_irq = mvebu_pcie_map_irq; + hw.map_irq = of_irq_parse_and_map_pci; hw.ops = &mvebu_pcie_ops; hw.align_resource = mvebu_pcie_align_resource; hw.add_bus = mvebu_pcie_add_bus; diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index a007321ad31..1b206eac5f9 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -30,6 +30,8 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/vmalloc.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/slab.h> diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 18c0d8d1ddf..182034d2ef5 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -48,7 +48,9 @@ #include <linux/interrupt.h> #include <linux/fsl_devices.h> #include <linux/bitops.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/io.h> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b6e864e8c9e..33f9dc1f14f 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -49,6 +49,35 @@ config PINCTRL_AB8505 bool "AB8505 pin controller driver" depends on PINCTRL_ABX500 && ARCH_U8500 +config PINCTRL_ADI2 + bool "ADI pin controller driver" + depends on BLACKFIN + select PINMUX + select IRQ_DOMAIN + help + This is the pin controller and gpio driver for ADI BF54x, BF60x and + future processors. This option is selected automatically when specific + machine and arch are selected to build. + +config PINCTRL_AS3722 + bool "Pinctrl and GPIO driver for ams AS3722 PMIC" + depends on MFD_AS3722 && GPIOLIB + select PINMUX + select GENERIC_PINCONF + help + AS3722 device supports the configuration of GPIO pins for different + functionality. This driver supports the pinmux, push-pull and + open drain configuration for the GPIO pins of AS3722 devices. It also + supports the GPIO functionality through gpiolib. + +config PINCTRL_BF54x + def_bool y if BF54x + select PINCTRL_ADI2 + +config PINCTRL_BF60x + def_bool y if BF60x + select PINCTRL_ADI2 + config PINCTRL_AT91 bool "AT91 pinctrl driver" depends on OF @@ -80,6 +109,19 @@ config PINCTRL_IMX select PINMUX select PINCONF +config PINCTRL_IMX1_CORE + bool + select PINMUX + select PINCONF + +config PINCTRL_IMX27 + bool "IMX27 pinctrl driver" + depends on OF + depends on SOC_IMX27 + select PINCTRL_IMX1_CORE + help + Say Y here to enable the imx27 pinctrl driver + config PINCTRL_IMX35 bool "IMX35 pinctrl driver" depends on OF @@ -88,6 +130,14 @@ config PINCTRL_IMX35 help Say Y here to enable the imx35 pinctrl driver +config PINCTRL_IMX50 + bool "IMX50 pinctrl driver" + depends on OF + depends on SOC_IMX50 + select PINCTRL_IMX + help + Say Y here to enable the imx50 pinctrl driver + config PINCTRL_IMX51 bool "IMX51 pinctrl driver" depends on OF @@ -292,6 +342,10 @@ config PINCTRL_XWAY depends on SOC_TYPE_XWAY depends on PINCTRL_LANTIQ +config PINCTRL_TB10X + bool + depends on ARC_PLAT_TB10X + endmenu endif diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 496d9bf9e1b..4f7be2921aa 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -14,11 +14,18 @@ obj-$(CONFIG_PINCTRL_AB8500) += pinctrl-ab8500.o obj-$(CONFIG_PINCTRL_AB8540) += pinctrl-ab8540.o obj-$(CONFIG_PINCTRL_AB9540) += pinctrl-ab9540.o obj-$(CONFIG_PINCTRL_AB8505) += pinctrl-ab8505.o +obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o +obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o +obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o +obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o +obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o +obj-$(CONFIG_PINCTRL_IMX27) += pinctrl-imx27.o obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o +obj-$(CONFIG_PINCTRL_IMX50) += pinctrl-imx50.o obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o @@ -52,6 +59,7 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 92f86ab30a1..5ee61a47001 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -462,6 +462,20 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname, } EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range); +int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group, + const unsigned **pins, unsigned *num_pins) +{ + const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; + int gs; + + gs = pinctrl_get_group_selector(pctldev, pin_group); + if (gs < 0) + return gs; + + return pctlops->get_group_pins(pctldev, gs, pins, num_pins); +} +EXPORT_SYMBOL_GPL(pinctrl_get_group_pins); + /** * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin * @pctldev: the pin controller device to look in diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c index 48e21a22948..ae1f760cbdd 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-370.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c @@ -408,7 +408,7 @@ static struct platform_driver armada_370_pinctrl_driver = { .driver = { .name = "armada-370-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(armada_370_pinctrl_of_match), + .of_match_table = armada_370_pinctrl_of_match, }, .probe = armada_370_pinctrl_probe, .remove = armada_370_pinctrl_remove, diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c index ab5dc04b3e8..843a51f9d12 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-xp.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c @@ -455,7 +455,7 @@ static struct platform_driver armada_xp_pinctrl_driver = { .driver = { .name = "armada-xp-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(armada_xp_pinctrl_of_match), + .of_match_table = armada_xp_pinctrl_of_match, }, .probe = armada_xp_pinctrl_probe, .remove = armada_xp_pinctrl_remove, diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index 29f7e4fc7ca..47268393af3 100644 --- a/drivers/pinctrl/mvebu/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c @@ -335,7 +335,7 @@ static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl *ctrl, unsigned long gcfg2 = readl(DOVE_GLOBAL_CONFIG_2); gcfg1 &= ~DOVE_TWSI_ENABLE_OPTION1; - gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION2); + gcfg2 &= ~(DOVE_TWSI_ENABLE_OPTION2 | DOVE_TWSI_ENABLE_OPTION3); switch (config) { case 1: @@ -806,7 +806,7 @@ static struct platform_driver dove_pinctrl_driver = { .driver = { .name = "dove-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(dove_pinctrl_of_match), + .of_match_table = dove_pinctrl_of_match, }, .probe = dove_pinctrl_probe, .remove = dove_pinctrl_remove, diff --git a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c index cdd483df673..6b504b5935a 100644 --- a/drivers/pinctrl/mvebu/pinctrl-kirkwood.c +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c @@ -471,7 +471,7 @@ static struct platform_driver kirkwood_pinctrl_driver = { .driver = { .name = "kirkwood-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(kirkwood_pinctrl_of_match), + .of_match_table = kirkwood_pinctrl_of_match, }, .probe = kirkwood_pinctrl_probe, .remove = kirkwood_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-adi2-bf54x.c b/drivers/pinctrl/pinctrl-adi2-bf54x.c new file mode 100644 index 00000000000..ea9d9ab9cda --- /dev/null +++ b/drivers/pinctrl/pinctrl-adi2-bf54x.c @@ -0,0 +1,592 @@ +/* + * Pinctrl Driver for ADI GPIO2 controller + * + * Copyright 2007-2013 Analog Devices Inc. + * + * Licensed under the GPLv2 or later + */ + +#include <asm/portmux.h> +#include "pinctrl-adi2.h" + +static const struct pinctrl_pin_desc adi_pads[] = { + PINCTRL_PIN(0, "PA0"), + PINCTRL_PIN(1, "PA1"), + PINCTRL_PIN(2, "PA2"), + PINCTRL_PIN(3, "PG3"), + PINCTRL_PIN(4, "PA4"), + PINCTRL_PIN(5, "PA5"), + PINCTRL_PIN(6, "PA6"), + PINCTRL_PIN(7, "PA7"), + PINCTRL_PIN(8, "PA8"), + PINCTRL_PIN(9, "PA9"), + PINCTRL_PIN(10, "PA10"), + PINCTRL_PIN(11, "PA11"), + PINCTRL_PIN(12, "PA12"), + PINCTRL_PIN(13, "PA13"), + PINCTRL_PIN(14, "PA14"), + PINCTRL_PIN(15, "PA15"), + PINCTRL_PIN(16, "PB0"), + PINCTRL_PIN(17, "PB1"), + PINCTRL_PIN(18, "PB2"), + PINCTRL_PIN(19, "PB3"), + PINCTRL_PIN(20, "PB4"), + PINCTRL_PIN(21, "PB5"), + PINCTRL_PIN(22, "PB6"), + PINCTRL_PIN(23, "PB7"), + PINCTRL_PIN(24, "PB8"), + PINCTRL_PIN(25, "PB9"), + PINCTRL_PIN(26, "PB10"), + PINCTRL_PIN(27, "PB11"), + PINCTRL_PIN(28, "PB12"), + PINCTRL_PIN(29, "PB13"), + PINCTRL_PIN(30, "PB14"), + PINCTRL_PIN(32, "PC0"), + PINCTRL_PIN(33, "PC1"), + PINCTRL_PIN(34, "PC2"), + PINCTRL_PIN(35, "PC3"), + PINCTRL_PIN(36, "PC4"), + PINCTRL_PIN(37, "PC5"), + PINCTRL_PIN(38, "PC6"), + PINCTRL_PIN(39, "PC7"), + PINCTRL_PIN(40, "PC8"), + PINCTRL_PIN(41, "PC9"), + PINCTRL_PIN(42, "PC10"), + PINCTRL_PIN(43, "PC11"), + PINCTRL_PIN(44, "PC12"), + PINCTRL_PIN(45, "PC13"), + PINCTRL_PIN(48, "PD0"), + PINCTRL_PIN(49, "PD1"), + PINCTRL_PIN(50, "PD2"), + PINCTRL_PIN(51, "PD3"), + PINCTRL_PIN(52, "PD4"), + PINCTRL_PIN(53, "PD5"), + PINCTRL_PIN(54, "PD6"), + PINCTRL_PIN(55, "PD7"), + PINCTRL_PIN(56, "PD8"), + PINCTRL_PIN(57, "PD9"), + PINCTRL_PIN(58, "PD10"), + PINCTRL_PIN(59, "PD11"), + PINCTRL_PIN(60, "PD12"), + PINCTRL_PIN(61, "PD13"), + PINCTRL_PIN(62, "PD14"), + PINCTRL_PIN(63, "PD15"), + PINCTRL_PIN(64, "PE0"), + PINCTRL_PIN(65, "PE1"), + PINCTRL_PIN(66, "PE2"), + PINCTRL_PIN(67, "PE3"), + PINCTRL_PIN(68, "PE4"), + PINCTRL_PIN(69, "PE5"), + PINCTRL_PIN(70, "PE6"), + PINCTRL_PIN(71, "PE7"), + PINCTRL_PIN(72, "PE8"), + PINCTRL_PIN(73, "PE9"), + PINCTRL_PIN(74, "PE10"), + PINCTRL_PIN(75, "PE11"), + PINCTRL_PIN(76, "PE12"), + PINCTRL_PIN(77, "PE13"), + PINCTRL_PIN(78, "PE14"), + PINCTRL_PIN(79, "PE15"), + PINCTRL_PIN(80, "PF0"), + PINCTRL_PIN(81, "PF1"), + PINCTRL_PIN(82, "PF2"), + PINCTRL_PIN(83, "PF3"), + PINCTRL_PIN(84, "PF4"), + PINCTRL_PIN(85, "PF5"), + PINCTRL_PIN(86, "PF6"), + PINCTRL_PIN(87, "PF7"), + PINCTRL_PIN(88, "PF8"), + PINCTRL_PIN(89, "PF9"), + PINCTRL_PIN(90, "PF10"), + PINCTRL_PIN(91, "PF11"), + PINCTRL_PIN(92, "PF12"), + PINCTRL_PIN(93, "PF13"), + PINCTRL_PIN(94, "PF14"), + PINCTRL_PIN(95, "PF15"), + PINCTRL_PIN(96, "PG0"), + PINCTRL_PIN(97, "PG1"), + PINCTRL_PIN(98, "PG2"), + PINCTRL_PIN(99, "PG3"), + PINCTRL_PIN(100, "PG4"), + PINCTRL_PIN(101, "PG5"), + PINCTRL_PIN(102, "PG6"), + PINCTRL_PIN(103, "PG7"), + PINCTRL_PIN(104, "PG8"), + PINCTRL_PIN(105, "PG9"), + PINCTRL_PIN(106, "PG10"), + PINCTRL_PIN(107, "PG11"), + PINCTRL_PIN(108, "PG12"), + PINCTRL_PIN(109, "PG13"), + PINCTRL_PIN(110, "PG14"), + PINCTRL_PIN(111, "PG15"), + PINCTRL_PIN(112, "PH0"), + PINCTRL_PIN(113, "PH1"), + PINCTRL_PIN(114, "PH2"), + PINCTRL_PIN(115, "PH3"), + PINCTRL_PIN(116, "PH4"), + PINCTRL_PIN(117, "PH5"), + PINCTRL_PIN(118, "PH6"), + PINCTRL_PIN(119, "PH7"), + PINCTRL_PIN(120, "PH8"), + PINCTRL_PIN(121, "PH9"), + PINCTRL_PIN(122, "PH10"), + PINCTRL_PIN(123, "PH11"), + PINCTRL_PIN(124, "PH12"), + PINCTRL_PIN(125, "PH13"), + PINCTRL_PIN(128, "PI0"), + PINCTRL_PIN(129, "PI1"), + PINCTRL_PIN(130, "PI2"), + PINCTRL_PIN(131, "PI3"), + PINCTRL_PIN(132, "PI4"), + PINCTRL_PIN(133, "PI5"), + PINCTRL_PIN(134, "PI6"), + PINCTRL_PIN(135, "PI7"), + PINCTRL_PIN(136, "PI8"), + PINCTRL_PIN(137, "PI9"), + PINCTRL_PIN(138, "PI10"), + PINCTRL_PIN(139, "PI11"), + PINCTRL_PIN(140, "PI12"), + PINCTRL_PIN(141, "PI13"), + PINCTRL_PIN(142, "PI14"), + PINCTRL_PIN(143, "PI15"), + PINCTRL_PIN(144, "PJ0"), + PINCTRL_PIN(145, "PJ1"), + PINCTRL_PIN(146, "PJ2"), + PINCTRL_PIN(147, "PJ3"), + PINCTRL_PIN(148, "PJ4"), + PINCTRL_PIN(149, "PJ5"), + PINCTRL_PIN(150, "PJ6"), + PINCTRL_PIN(151, "PJ7"), + PINCTRL_PIN(152, "PJ8"), + PINCTRL_PIN(153, "PJ9"), + PINCTRL_PIN(154, "PJ10"), + PINCTRL_PIN(155, "PJ11"), + PINCTRL_PIN(156, "PJ12"), + PINCTRL_PIN(157, "PJ13"), +}; + +static const unsigned uart0_pins[] = { + GPIO_PE7, GPIO_PE8, +}; + +static const unsigned uart1_pins[] = { + GPIO_PH0, GPIO_PH1, +}; + +static const unsigned uart1_ctsrts_pins[] = { + GPIO_PE9, GPIO_PE10, +}; + +static const unsigned uart2_pins[] = { + GPIO_PB4, GPIO_PB5, +}; + +static const unsigned uart3_pins[] = { + GPIO_PB6, GPIO_PB7, +}; + +static const unsigned uart3_ctsrts_pins[] = { + GPIO_PB2, GPIO_PB3, +}; + +static const unsigned rsi0_pins[] = { + GPIO_PC8, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12, GPIO_PC13, +}; + +static const unsigned spi0_pins[] = { + GPIO_PE0, GPIO_PE1, GPIO_PE2, +}; + +static const unsigned spi1_pins[] = { + GPIO_PG8, GPIO_PG9, GPIO_PG10, +}; + +static const unsigned twi0_pins[] = { + GPIO_PE14, GPIO_PE15, +}; + +static const unsigned twi1_pins[] = { + GPIO_PB0, GPIO_PB1, +}; + +static const unsigned rotary_pins[] = { + GPIO_PH4, GPIO_PH3, GPIO_PH5, +}; + +static const unsigned can0_pins[] = { + GPIO_PG13, GPIO_PG12, +}; + +static const unsigned can1_pins[] = { + GPIO_PG14, GPIO_PG15, +}; + +static const unsigned smc0_pins[] = { + GPIO_PH8, GPIO_PH9, GPIO_PH10, GPIO_PH11, GPIO_PH12, GPIO_PH13, + GPIO_PI0, GPIO_PI1, GPIO_PI2, GPIO_PI3, GPIO_PI4, GPIO_PI5, GPIO_PI6, + GPIO_PI7, GPIO_PI8, GPIO_PI9, GPIO_PI10, GPIO_PI11, + GPIO_PI12, GPIO_PI13, GPIO_PI14, GPIO_PI15, +}; + +static const unsigned sport0_pins[] = { + GPIO_PC0, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC6, GPIO_PC7, +}; + +static const unsigned sport1_pins[] = { + GPIO_PD0, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD6, GPIO_PD7, +}; + +static const unsigned sport2_pins[] = { + GPIO_PA0, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA6, GPIO_PA7, +}; + +static const unsigned sport3_pins[] = { + GPIO_PA8, GPIO_PA10, GPIO_PA11, GPIO_PA12, GPIO_PA14, GPIO_PA15, +}; + +static const unsigned ppi0_8b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF13, GPIO_PG0, GPIO_PG1, GPIO_PG2, +}; + +static const unsigned ppi0_16b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12, + GPIO_PF13, GPIO_PF14, GPIO_PF15, + GPIO_PG0, GPIO_PG1, GPIO_PG2, +}; + +static const unsigned ppi0_24b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12, + GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PD0, GPIO_PD1, GPIO_PD2, + GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PG3, GPIO_PG4, + GPIO_PG0, GPIO_PG1, GPIO_PG2, +}; + +static const unsigned ppi1_8b_pins[] = { + GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6, + GPIO_PD7, GPIO_PE11, GPIO_PE12, GPIO_PE13, +}; + +static const unsigned ppi1_16b_pins[] = { + GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6, + GPIO_PD7, GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12, + GPIO_PD13, GPIO_PD14, GPIO_PD15, + GPIO_PE11, GPIO_PE12, GPIO_PE13, +}; + +static const unsigned ppi2_8b_pins[] = { + GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12, + GPIO_PD13, GPIO_PD14, GPIO_PD15, + GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3, +}; + +static const unsigned atapi_pins[] = { + GPIO_PH2, GPIO_PJ3, GPIO_PJ4, GPIO_PJ5, GPIO_PJ6, + GPIO_PJ7, GPIO_PJ8, GPIO_PJ9, GPIO_PJ10, +}; + +static const unsigned atapi_alter_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12, + GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PG2, GPIO_PG3, GPIO_PG4, +}; + +static const unsigned nfc0_pins[] = { + GPIO_PJ1, GPIO_PJ2, +}; + +static const unsigned keys_4x4_pins[] = { + GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, + GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15, +}; + +static const unsigned keys_8x8_pins[] = { + GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, + GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15, + GPIO_PE0, GPIO_PE1, GPIO_PE2, GPIO_PE3, + GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7, +}; + +static const struct adi_pin_group adi_pin_groups[] = { + ADI_PIN_GROUP("uart0grp", uart0_pins), + ADI_PIN_GROUP("uart1grp", uart1_pins), + ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins), + ADI_PIN_GROUP("uart2grp", uart2_pins), + ADI_PIN_GROUP("uart3grp", uart3_pins), + ADI_PIN_GROUP("uart3ctsrtsgrp", uart3_ctsrts_pins), + ADI_PIN_GROUP("rsi0grp", rsi0_pins), + ADI_PIN_GROUP("spi0grp", spi0_pins), + ADI_PIN_GROUP("spi1grp", spi1_pins), + ADI_PIN_GROUP("twi0grp", twi0_pins), + ADI_PIN_GROUP("twi1grp", twi1_pins), + ADI_PIN_GROUP("rotarygrp", rotary_pins), + ADI_PIN_GROUP("can0grp", can0_pins), + ADI_PIN_GROUP("can1grp", can1_pins), + ADI_PIN_GROUP("smc0grp", smc0_pins), + ADI_PIN_GROUP("sport0grp", sport0_pins), + ADI_PIN_GROUP("sport1grp", sport1_pins), + ADI_PIN_GROUP("sport2grp", sport2_pins), + ADI_PIN_GROUP("sport3grp", sport3_pins), + ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins), + ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins), + ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins), + ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins), + ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins), + ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins), + ADI_PIN_GROUP("atapigrp", atapi_pins), + ADI_PIN_GROUP("atapialtergrp", atapi_alter_pins), + ADI_PIN_GROUP("nfc0grp", nfc0_pins), + ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins), + ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins), +}; + +static const unsigned short uart0_mux[] = { + P_UART0_TX, P_UART0_RX, + 0 +}; + +static const unsigned short uart1_mux[] = { + P_UART1_TX, P_UART1_RX, + 0 +}; + +static const unsigned short uart1_ctsrts_mux[] = { + P_UART1_RTS, P_UART1_CTS, + 0 +}; + +static const unsigned short uart2_mux[] = { + P_UART2_TX, P_UART2_RX, + 0 +}; + +static const unsigned short uart3_mux[] = { + P_UART3_TX, P_UART3_RX, + 0 +}; + +static const unsigned short uart3_ctsrts_mux[] = { + P_UART3_RTS, P_UART3_CTS, + 0 +}; + +static const unsigned short rsi0_mux[] = { + P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD, + 0 +}; + +static const unsigned short spi0_mux[] = { + P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0 +}; + +static const unsigned short spi1_mux[] = { + P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0 +}; + +static const unsigned short twi0_mux[] = { + P_TWI0_SCL, P_TWI0_SDA, 0 +}; + +static const unsigned short twi1_mux[] = { + P_TWI1_SCL, P_TWI1_SDA, 0 +}; + +static const unsigned short rotary_mux[] = { + P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0 +}; + +static const unsigned short sport0_mux[] = { + P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, + P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0 +}; + +static const unsigned short sport1_mux[] = { + P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, + P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0 +}; + +static const unsigned short sport2_mux[] = { + P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS, + P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0 +}; + +static const unsigned short sport3_mux[] = { + P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS, + P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0 +}; + +static const unsigned short can0_mux[] = { + P_CAN0_RX, P_CAN0_TX, 0 +}; + +static const unsigned short can1_mux[] = { + P_CAN1_RX, P_CAN1_TX, 0 +}; + +static const unsigned short smc0_mux[] = { + P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12, + P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21, + P_A22, P_A23, P_A24, P_A25, P_NOR_CLK, 0, +}; + +static const unsigned short ppi0_8b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi0_16b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi0_24b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, + P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19, + P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi1_8b_mux[] = { + P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3, + P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7, + P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2, + 0, +}; + +static const unsigned short ppi1_16b_mux[] = { + P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3, + P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7, + P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11, + P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15, + P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2, + 0, +}; + +static const unsigned short ppi2_8b_mux[] = { + P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3, + P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7, + P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2, + 0, +}; + +static const unsigned short atapi_mux[] = { + P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, P_ATAPI_CS1, + P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, P_ATAPI_IORDY, +}; + +static const unsigned short atapi_alter_mux[] = { + P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A, P_ATAPI_D3A, P_ATAPI_D4A, + P_ATAPI_D5A, P_ATAPI_D6A, P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A, + P_ATAPI_D10A, P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A, + P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A, + 0 +}; + +static const unsigned short nfc0_mux[] = { + P_NAND_CE, P_NAND_RB, + 0 +}; + +static const unsigned short keys_4x4_mux[] = { + P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0, + P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0, + 0 +}; + +static const unsigned short keys_8x8_mux[] = { + P_KEY_ROW7, P_KEY_ROW6, P_KEY_ROW5, P_KEY_ROW4, + P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0, + P_KEY_COL7, P_KEY_COL6, P_KEY_COL5, P_KEY_COL4, + P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0, + 0 +}; + +static const char * const uart0grp[] = { "uart0grp" }; +static const char * const uart1grp[] = { "uart1grp" }; +static const char * const uart1ctsrtsgrp[] = { "uart1ctsrtsgrp" }; +static const char * const uart2grp[] = { "uart2grp" }; +static const char * const uart3grp[] = { "uart3grp" }; +static const char * const uart3ctsrtsgrp[] = { "uart3ctsrtsgrp" }; +static const char * const rsi0grp[] = { "rsi0grp" }; +static const char * const spi0grp[] = { "spi0grp" }; +static const char * const spi1grp[] = { "spi1grp" }; +static const char * const twi0grp[] = { "twi0grp" }; +static const char * const twi1grp[] = { "twi1grp" }; +static const char * const rotarygrp[] = { "rotarygrp" }; +static const char * const can0grp[] = { "can0grp" }; +static const char * const can1grp[] = { "can1grp" }; +static const char * const smc0grp[] = { "smc0grp" }; +static const char * const sport0grp[] = { "sport0grp" }; +static const char * const sport1grp[] = { "sport1grp" }; +static const char * const sport2grp[] = { "sport2grp" }; +static const char * const sport3grp[] = { "sport3grp" }; +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" }; +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" }; +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" }; +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" }; +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" }; +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" }; +static const char * const atapigrp[] = { "atapigrp" }; +static const char * const atapialtergrp[] = { "atapialtergrp" }; +static const char * const nfc0grp[] = { "nfc0grp" }; +static const char * const keys_4x4grp[] = { "keys_4x4grp" }; +static const char * const keys_8x8grp[] = { "keys_8x8grp" }; + +static const struct adi_pmx_func adi_pmx_functions[] = { + ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux), + ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux), + ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux), + ADI_PMX_FUNCTION("uart2", uart2grp, uart2_mux), + ADI_PMX_FUNCTION("uart3", uart3grp, uart3_mux), + ADI_PMX_FUNCTION("uart3_ctsrts", uart3ctsrtsgrp, uart3_ctsrts_mux), + ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux), + ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux), + ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux), + ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux), + ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux), + ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux), + ADI_PMX_FUNCTION("can0", can0grp, can0_mux), + ADI_PMX_FUNCTION("can1", can1grp, can1_mux), + ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux), + ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux), + ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux), + ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux), + ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux), + ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux), + ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux), + ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux), + ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux), + ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux), + ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux), + ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux), + ADI_PMX_FUNCTION("atapi_alter", atapialtergrp, atapi_alter_mux), + ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux), + ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux), + ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux), +}; + +static const struct adi_pinctrl_soc_data adi_bf54x_soc = { + .functions = adi_pmx_functions, + .nfunctions = ARRAY_SIZE(adi_pmx_functions), + .groups = adi_pin_groups, + .ngroups = ARRAY_SIZE(adi_pin_groups), + .pins = adi_pads, + .npins = ARRAY_SIZE(adi_pads), +}; + +void adi_pinctrl_soc_init(const struct adi_pinctrl_soc_data **soc) +{ + *soc = &adi_bf54x_soc; +} diff --git a/drivers/pinctrl/pinctrl-adi2-bf60x.c b/drivers/pinctrl/pinctrl-adi2-bf60x.c new file mode 100644 index 00000000000..bf57aea2826 --- /dev/null +++ b/drivers/pinctrl/pinctrl-adi2-bf60x.c @@ -0,0 +1,521 @@ +/* + * Pinctrl Driver for ADI GPIO2 controller + * + * Copyright 2007-2013 Analog Devices Inc. + * + * Licensed under the GPLv2 or later + */ + +#include <asm/portmux.h> +#include "pinctrl-adi2.h" + +static const struct pinctrl_pin_desc adi_pads[] = { + PINCTRL_PIN(0, "PA0"), + PINCTRL_PIN(1, "PA1"), + PINCTRL_PIN(2, "PA2"), + PINCTRL_PIN(3, "PG3"), + PINCTRL_PIN(4, "PA4"), + PINCTRL_PIN(5, "PA5"), + PINCTRL_PIN(6, "PA6"), + PINCTRL_PIN(7, "PA7"), + PINCTRL_PIN(8, "PA8"), + PINCTRL_PIN(9, "PA9"), + PINCTRL_PIN(10, "PA10"), + PINCTRL_PIN(11, "PA11"), + PINCTRL_PIN(12, "PA12"), + PINCTRL_PIN(13, "PA13"), + PINCTRL_PIN(14, "PA14"), + PINCTRL_PIN(15, "PA15"), + PINCTRL_PIN(16, "PB0"), + PINCTRL_PIN(17, "PB1"), + PINCTRL_PIN(18, "PB2"), + PINCTRL_PIN(19, "PB3"), + PINCTRL_PIN(20, "PB4"), + PINCTRL_PIN(21, "PB5"), + PINCTRL_PIN(22, "PB6"), + PINCTRL_PIN(23, "PB7"), + PINCTRL_PIN(24, "PB8"), + PINCTRL_PIN(25, "PB9"), + PINCTRL_PIN(26, "PB10"), + PINCTRL_PIN(27, "PB11"), + PINCTRL_PIN(28, "PB12"), + PINCTRL_PIN(29, "PB13"), + PINCTRL_PIN(30, "PB14"), + PINCTRL_PIN(31, "PB15"), + PINCTRL_PIN(32, "PC0"), + PINCTRL_PIN(33, "PC1"), + PINCTRL_PIN(34, "PC2"), + PINCTRL_PIN(35, "PC3"), + PINCTRL_PIN(36, "PC4"), + PINCTRL_PIN(37, "PC5"), + PINCTRL_PIN(38, "PC6"), + PINCTRL_PIN(39, "PC7"), + PINCTRL_PIN(40, "PC8"), + PINCTRL_PIN(41, "PC9"), + PINCTRL_PIN(42, "PC10"), + PINCTRL_PIN(43, "PC11"), + PINCTRL_PIN(44, "PC12"), + PINCTRL_PIN(45, "PC13"), + PINCTRL_PIN(46, "PC14"), + PINCTRL_PIN(47, "PC15"), + PINCTRL_PIN(48, "PD0"), + PINCTRL_PIN(49, "PD1"), + PINCTRL_PIN(50, "PD2"), + PINCTRL_PIN(51, "PD3"), + PINCTRL_PIN(52, "PD4"), + PINCTRL_PIN(53, "PD5"), + PINCTRL_PIN(54, "PD6"), + PINCTRL_PIN(55, "PD7"), + PINCTRL_PIN(56, "PD8"), + PINCTRL_PIN(57, "PD9"), + PINCTRL_PIN(58, "PD10"), + PINCTRL_PIN(59, "PD11"), + PINCTRL_PIN(60, "PD12"), + PINCTRL_PIN(61, "PD13"), + PINCTRL_PIN(62, "PD14"), + PINCTRL_PIN(63, "PD15"), + PINCTRL_PIN(64, "PE0"), + PINCTRL_PIN(65, "PE1"), + PINCTRL_PIN(66, "PE2"), + PINCTRL_PIN(67, "PE3"), + PINCTRL_PIN(68, "PE4"), + PINCTRL_PIN(69, "PE5"), + PINCTRL_PIN(70, "PE6"), + PINCTRL_PIN(71, "PE7"), + PINCTRL_PIN(72, "PE8"), + PINCTRL_PIN(73, "PE9"), + PINCTRL_PIN(74, "PE10"), + PINCTRL_PIN(75, "PE11"), + PINCTRL_PIN(76, "PE12"), + PINCTRL_PIN(77, "PE13"), + PINCTRL_PIN(78, "PE14"), + PINCTRL_PIN(79, "PE15"), + PINCTRL_PIN(80, "PF0"), + PINCTRL_PIN(81, "PF1"), + PINCTRL_PIN(82, "PF2"), + PINCTRL_PIN(83, "PF3"), + PINCTRL_PIN(84, "PF4"), + PINCTRL_PIN(85, "PF5"), + PINCTRL_PIN(86, "PF6"), + PINCTRL_PIN(87, "PF7"), + PINCTRL_PIN(88, "PF8"), + PINCTRL_PIN(89, "PF9"), + PINCTRL_PIN(90, "PF10"), + PINCTRL_PIN(91, "PF11"), + PINCTRL_PIN(92, "PF12"), + PINCTRL_PIN(93, "PF13"), + PINCTRL_PIN(94, "PF14"), + PINCTRL_PIN(95, "PF15"), + PINCTRL_PIN(96, "PG0"), + PINCTRL_PIN(97, "PG1"), + PINCTRL_PIN(98, "PG2"), + PINCTRL_PIN(99, "PG3"), + PINCTRL_PIN(100, "PG4"), + PINCTRL_PIN(101, "PG5"), + PINCTRL_PIN(102, "PG6"), + PINCTRL_PIN(103, "PG7"), + PINCTRL_PIN(104, "PG8"), + PINCTRL_PIN(105, "PG9"), + PINCTRL_PIN(106, "PG10"), + PINCTRL_PIN(107, "PG11"), + PINCTRL_PIN(108, "PG12"), + PINCTRL_PIN(109, "PG13"), + PINCTRL_PIN(110, "PG14"), + PINCTRL_PIN(111, "PG15"), +}; + +static const unsigned uart0_pins[] = { + GPIO_PD7, GPIO_PD8, +}; + +static const unsigned uart0_ctsrts_pins[] = { + GPIO_PD9, GPIO_PD10, +}; + +static const unsigned uart1_pins[] = { + GPIO_PG15, GPIO_PG14, +}; + +static const unsigned uart1_ctsrts_pins[] = { + GPIO_PG10, GPIO_PG13, +}; + +static const unsigned rsi0_pins[] = { + GPIO_PG3, GPIO_PG2, GPIO_PG0, GPIO_PE15, GPIO_PG5, GPIO_PG6, +}; + +static const unsigned eth0_pins[] = { + GPIO_PC6, GPIO_PC7, GPIO_PC2, GPIO_PC0, GPIO_PC3, GPIO_PC1, + GPIO_PB13, GPIO_PD6, GPIO_PC5, GPIO_PC4, GPIO_PB14, GPIO_PB15, +}; + +static const unsigned eth1_pins[] = { + GPIO_PE10, GPIO_PE11, GPIO_PG3, GPIO_PG0, GPIO_PG2, GPIO_PE15, + GPIO_PG5, GPIO_PE12, GPIO_PE13, GPIO_PE14, GPIO_PG6, GPIO_PC9, +}; + +static const unsigned spi0_pins[] = { + GPIO_PD4, GPIO_PD2, GPIO_PD3, +}; + +static const unsigned spi1_pins[] = { + GPIO_PD5, GPIO_PD14, GPIO_PD13, +}; + +static const unsigned twi0_pins[] = { +}; + +static const unsigned twi1_pins[] = { +}; + +static const unsigned rotary_pins[] = { + GPIO_PG7, GPIO_PG11, GPIO_PG12, +}; + +static const unsigned can0_pins[] = { + GPIO_PG1, GPIO_PG4, +}; + +static const unsigned smc0_pins[] = { + GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6, + GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PB2, GPIO_PA10, GPIO_PA11, + GPIO_PB3, GPIO_PA12, GPIO_PA13, GPIO_PA14, GPIO_PA15, GPIO_PB6, + GPIO_PB7, GPIO_PB8, GPIO_PB10, GPIO_PB11, GPIO_PB0, +}; + +static const unsigned sport0_pins[] = { + GPIO_PB5, GPIO_PB4, GPIO_PB9, GPIO_PB8, GPIO_PB7, GPIO_PB11, +}; + +static const unsigned sport1_pins[] = { + GPIO_PE2, GPIO_PE5, GPIO_PD15, GPIO_PE4, GPIO_PE3, GPIO_PE1, +}; + +static const unsigned sport2_pins[] = { + GPIO_PG4, GPIO_PG1, GPIO_PG9, GPIO_PG10, GPIO_PG7, GPIO_PB12, +}; + +static const unsigned ppi0_8b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF13, GPIO_PF14, GPIO_PF15, + GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9, +}; + +static const unsigned ppi0_16b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12, + GPIO_PF13, GPIO_PF14, GPIO_PF15, + GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9, +}; + +static const unsigned ppi0_24b_pins[] = { + GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6, + GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12, + GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PE0, GPIO_PE1, GPIO_PE2, + GPIO_PE3, GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7, GPIO_PE8, + GPIO_PE9, GPIO_PD12, GPIO_PD15, +}; + +static const unsigned ppi1_8b_pins[] = { + GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6, + GPIO_PC7, GPIO_PC8, GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6, +}; + +static const unsigned ppi1_16b_pins[] = { + GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6, + GPIO_PC7, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12, + GPIO_PC13, GPIO_PC14, GPIO_PC15, + GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6, +}; + +static const unsigned ppi2_8b_pins[] = { + GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6, + GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3, +}; + +static const unsigned ppi2_16b_pins[] = { + GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6, + GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PA10, GPIO_PA11, GPIO_PA12, + GPIO_PA13, GPIO_PA14, GPIO_PA15, GPIO_PB0, GPIO_PB1, GPIO_PB2, +}; + +static const unsigned lp0_pins[] = { + GPIO_PB0, GPIO_PB1, GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, + GPIO_PA4, GPIO_PA5, GPIO_PA6, GPIO_PA7, +}; + +static const unsigned lp1_pins[] = { + GPIO_PB3, GPIO_PB2, GPIO_PA8, GPIO_PA9, GPIO_PA10, GPIO_PA11, + GPIO_PA12, GPIO_PA13, GPIO_PA14, GPIO_PA15, +}; + +static const unsigned lp2_pins[] = { + GPIO_PE6, GPIO_PE7, GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, + GPIO_PF4, GPIO_PF5, GPIO_PF6, GPIO_PF7, +}; + +static const unsigned lp3_pins[] = { + GPIO_PE9, GPIO_PE8, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, + GPIO_PF12, GPIO_PF13, GPIO_PF14, GPIO_PF15, +}; + +static const struct adi_pin_group adi_pin_groups[] = { + ADI_PIN_GROUP("uart0grp", uart0_pins), + ADI_PIN_GROUP("uart0ctsrtsgrp", uart0_ctsrts_pins), + ADI_PIN_GROUP("uart1grp", uart1_pins), + ADI_PIN_GROUP("uart1ctsrtsgrp", uart1_ctsrts_pins), + ADI_PIN_GROUP("rsi0grp", rsi0_pins), + ADI_PIN_GROUP("eth0grp", eth0_pins), + ADI_PIN_GROUP("eth1grp", eth1_pins), + ADI_PIN_GROUP("spi0grp", spi0_pins), + ADI_PIN_GROUP("spi1grp", spi1_pins), + ADI_PIN_GROUP("twi0grp", twi0_pins), + ADI_PIN_GROUP("twi1grp", twi1_pins), + ADI_PIN_GROUP("rotarygrp", rotary_pins), + ADI_PIN_GROUP("can0grp", can0_pins), + ADI_PIN_GROUP("smc0grp", smc0_pins), + ADI_PIN_GROUP("sport0grp", sport0_pins), + ADI_PIN_GROUP("sport1grp", sport1_pins), + ADI_PIN_GROUP("sport2grp", sport2_pins), + ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins), + ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins), + ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins), + ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins), + ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins), + ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins), + ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins), + ADI_PIN_GROUP("lp0grp", lp0_pins), + ADI_PIN_GROUP("lp1grp", lp1_pins), + ADI_PIN_GROUP("lp2grp", lp2_pins), + ADI_PIN_GROUP("lp3grp", lp3_pins), +}; + +static const unsigned short uart0_mux[] = { + P_UART0_TX, P_UART0_RX, + 0 +}; + +static const unsigned short uart0_ctsrts_mux[] = { + P_UART0_RTS, P_UART0_CTS, + 0 +}; + +static const unsigned short uart1_mux[] = { + P_UART1_TX, P_UART1_RX, + 0 +}; + +static const unsigned short uart1_ctsrts_mux[] = { + P_UART1_RTS, P_UART1_CTS, + 0 +}; + +static const unsigned short rsi0_mux[] = { + P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3, + P_RSI_CMD, P_RSI_CLK, 0 +}; + +static const unsigned short eth0_mux[] = P_RMII0; +static const unsigned short eth1_mux[] = P_RMII1; + +static const unsigned short spi0_mux[] = { + P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0 +}; + +static const unsigned short spi1_mux[] = { + P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0 +}; + +static const unsigned short twi0_mux[] = { + P_TWI0_SCL, P_TWI0_SDA, 0 +}; + +static const unsigned short twi1_mux[] = { + P_TWI1_SCL, P_TWI1_SDA, 0 +}; + +static const unsigned short rotary_mux[] = { + P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0 +}; + +static const unsigned short sport0_mux[] = { + P_SPORT0_ACLK, P_SPORT0_AFS, P_SPORT0_AD0, P_SPORT0_BCLK, + P_SPORT0_BFS, P_SPORT0_BD0, 0, +}; + +static const unsigned short sport1_mux[] = { + P_SPORT1_ACLK, P_SPORT1_AFS, P_SPORT1_AD0, P_SPORT1_BCLK, + P_SPORT1_BFS, P_SPORT1_BD0, 0, +}; + +static const unsigned short sport2_mux[] = { + P_SPORT2_ACLK, P_SPORT2_AFS, P_SPORT2_AD0, P_SPORT2_BCLK, + P_SPORT2_BFS, P_SPORT2_BD0, 0, +}; + +static const unsigned short can0_mux[] = { + P_CAN0_RX, P_CAN0_TX, 0 +}; + +static const unsigned short smc0_mux[] = { + P_A3, P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12, + P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21, + P_A22, P_A23, P_A24, P_A25, P_NORCK, 0, +}; + +static const unsigned short ppi0_8b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi0_16b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi0_24b_mux[] = { + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, + P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, + P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, + P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19, + P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, + P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + 0, +}; + +static const unsigned short ppi1_8b_mux[] = { + P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3, + P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7, + P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2, + 0, +}; + +static const unsigned short ppi1_16b_mux[] = { + P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3, + P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7, + P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11, + P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15, + P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2, + 0, +}; + +static const unsigned short ppi2_8b_mux[] = { + P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3, + P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7, + P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2, + 0, +}; + +static const unsigned short ppi2_16b_mux[] = { + P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3, + P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7, + P_PPI2_D8, P_PPI2_D9, P_PPI2_D10, P_PPI2_D11, + P_PPI2_D12, P_PPI2_D13, P_PPI2_D14, P_PPI2_D15, + P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2, + 0, +}; + +static const unsigned short lp0_mux[] = { + P_LP0_CLK, P_LP0_ACK, P_LP0_D0, P_LP0_D1, P_LP0_D2, + P_LP0_D3, P_LP0_D4, P_LP0_D5, P_LP0_D6, P_LP0_D7, + 0 +}; + +static const unsigned short lp1_mux[] = { + P_LP1_CLK, P_LP1_ACK, P_LP1_D0, P_LP1_D1, P_LP1_D2, + P_LP1_D3, P_LP1_D4, P_LP1_D5, P_LP1_D6, P_LP1_D7, + 0 +}; + +static const unsigned short lp2_mux[] = { + P_LP2_CLK, P_LP2_ACK, P_LP2_D0, P_LP2_D1, P_LP2_D2, + P_LP2_D3, P_LP2_D4, P_LP2_D5, P_LP2_D6, P_LP2_D7, + 0 +}; + +static const unsigned short lp3_mux[] = { + P_LP3_CLK, P_LP3_ACK, P_LP3_D0, P_LP3_D1, P_LP3_D2, + P_LP3_D3, P_LP3_D4, P_LP3_D5, P_LP3_D6, P_LP3_D7, + 0 +}; + +static const char * const uart0grp[] = { "uart0grp" }; +static const char * const uart0ctsrtsgrp[] = { "uart0ctsrtsgrp" }; +static const char * const uart1grp[] = { "uart1grp" }; +static const char * const uart1ctsrtsgrp[] = { "uart1ctsrtsgrp" }; +static const char * const rsi0grp[] = { "rsi0grp" }; +static const char * const eth0grp[] = { "eth0grp" }; +static const char * const eth1grp[] = { "eth1grp" }; +static const char * const spi0grp[] = { "spi0grp" }; +static const char * const spi1grp[] = { "spi1grp" }; +static const char * const twi0grp[] = { "twi0grp" }; +static const char * const twi1grp[] = { "twi1grp" }; +static const char * const rotarygrp[] = { "rotarygrp" }; +static const char * const can0grp[] = { "can0grp" }; +static const char * const smc0grp[] = { "smc0grp" }; +static const char * const sport0grp[] = { "sport0grp" }; +static const char * const sport1grp[] = { "sport1grp" }; +static const char * const sport2grp[] = { "sport2grp" }; +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" }; +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" }; +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" }; +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" }; +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" }; +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" }; +static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" }; +static const char * const lp0grp[] = { "lp0grp" }; +static const char * const lp1grp[] = { "lp1grp" }; +static const char * const lp2grp[] = { "lp2grp" }; +static const char * const lp3grp[] = { "lp3grp" }; + +static const struct adi_pmx_func adi_pmx_functions[] = { + ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux), + ADI_PMX_FUNCTION("uart0_ctsrts", uart0ctsrtsgrp, uart0_ctsrts_mux), + ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux), + ADI_PMX_FUNCTION("uart1_ctsrts", uart1ctsrtsgrp, uart1_ctsrts_mux), + ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux), + ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux), + ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux), + ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux), + ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux), + ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux), + ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux), + ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux), + ADI_PMX_FUNCTION("can0", can0grp, can0_mux), + ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux), + ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux), + ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux), + ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux), + ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux), + ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux), + ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux), + ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux), + ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux), + ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux), + ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux), + ADI_PMX_FUNCTION("lp0", lp0grp, lp0_mux), + ADI_PMX_FUNCTION("lp1", lp1grp, lp1_mux), + ADI_PMX_FUNCTION("lp2", lp2grp, lp2_mux), + ADI_PMX_FUNCTION("lp3", lp3grp, lp3_mux), +}; + +static const struct adi_pinctrl_soc_data adi_bf60x_soc = { + .functions = adi_pmx_functions, + .nfunctions = ARRAY_SIZE(adi_pmx_functions), + .groups = adi_pin_groups, + .ngroups = ARRAY_SIZE(adi_pin_groups), + .pins = adi_pads, + .npins = ARRAY_SIZE(adi_pads), +}; + +void adi_pinctrl_soc_init(const struct adi_pinctrl_soc_data **soc) +{ + *soc = &adi_bf60x_soc; +} diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c new file mode 100644 index 00000000000..7a39562c3e4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -0,0 +1,1164 @@ +/* + * Pinctrl Driver for ADI GPIO2 controller + * + * Copyright 2007-2013 Analog Devices Inc. + * + * Licensed under the GPLv2 or later + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/irq.h> +#include <linux/platform_data/pinctrl-adi2.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> +#include <linux/syscore_ops.h> +#include <linux/gpio.h> +#include <asm/portmux.h> +#include "pinctrl-adi2.h" +#include "core.h" + +/* +According to the BF54x HRM, pint means "pin interrupt". +http://www.analog.com/static/imported-files/processor_manuals/ADSP-BF54x_hwr_rev1.2.pdf + +ADSP-BF54x processor Blackfin processors have four SIC interrupt chan- +nels dedicated to pin interrupt purposes. These channels are managed by +four hardware blocks, called PINT0, PINT1, PINT2, and PINT3. Every PINTx +block can sense to up to 32 pins. While PINT0 and PINT1 can sense the +pins of port A and port B, PINT2 and PINT3 manage all the pins from port +C to port J as shown in Figure 9-2. + +n BF54x HRM: +The ten GPIO ports are subdivided into 8-bit half ports, resulting in lower and +upper half 8-bit units. The PINTx_ASSIGN registers control the 8-bit multi- +plexers shown in Figure 9-3. Lower half units of eight pins can be +forwarded to either byte 0 or byte 2 of either associated PINTx block. +Upper half units can be forwarded to either byte 1 or byte 3 of the pin +interrupt blocks, without further restrictions. + +All MMR registers in the pin interrupt module are 32 bits wide. To simply the +mapping logic, this driver only maps a 16-bit gpio port to the upper or lower +16 bits of a PINTx block. You can find the Figure 9-3 on page 583. + +Each IRQ domain is binding to a GPIO bank device. 2 GPIO bank devices can map +to one PINT device. Two in "struct gpio_pint" are used to ease the PINT +interrupt handler. + +The GPIO bank mapping to the lower 16 bits of the PINT device set its IRQ +domain pointer in domain[0]. The IRQ domain pointer of the other bank is set +to domain[1]. PINT interrupt handler adi_gpio_handle_pint_irq() finds out +the current domain pointer according to whether the interrupt request mask +is in lower 16 bits (domain[0]) or upper 16bits (domain[1]). + +A PINT device is not part of a GPIO port device in Blackfin. Multiple GPIO +port devices can be mapped to the same PINT device. + +*/ + +static LIST_HEAD(adi_pint_list); +static LIST_HEAD(adi_gpio_port_list); + +#define DRIVER_NAME "pinctrl-adi2" + +#define PINT_HI_OFFSET 16 + +/** + * struct gpio_port_saved - GPIO port registers that should be saved between + * power suspend and resume operations. + * + * @fer: PORTx_FER register + * @data: PORTx_DATA register + * @dir: PORTx_DIR register + * @inen: PORTx_INEN register + * @mux: PORTx_MUX register + */ +struct gpio_port_saved { + u16 fer; + u16 data; + u16 dir; + u16 inen; + u32 mux; +}; + +/** + * struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO + * banks can be mapped into one Pin interrupt controller. + * + * @node: All gpio_pint instances are added to a global list. + * @base: PINT device register base address + * @irq: IRQ of the PINT device, it is the parent IRQ of all + * GPIO IRQs mapping to this device. + * @domain: [0] irq domain of the gpio port, whose hardware interrupts are + * mapping to the low 16-bit of the pint registers. + * [1] irq domain of the gpio port, whose hardware interrupts are + * mapping to the high 16-bit of the pint registers. + * @regs: address pointer to the PINT device + * @map_count: No more than 2 GPIO banks can be mapped to this PINT device. + * @lock: This lock make sure the irq_chip operations to one PINT device + * for different GPIO interrrupts are atomic. + * @pint_map_port: Set up the mapping between one PINT device and + * multiple GPIO banks. + */ +struct gpio_pint { + struct list_head node; + void __iomem *base; + int irq; + struct irq_domain *domain[2]; + struct gpio_pint_regs *regs; + struct adi_pm_pint_save saved_data; + int map_count; + spinlock_t lock; + + int (*pint_map_port)(struct gpio_pint *pint, bool assign, + u8 map, struct irq_domain *domain); +}; + +/** + * ADI pin controller + * + * @dev: a pointer back to containing device + * @pctl: the pinctrl device + * @soc: SoC data for this specific chip + */ +struct adi_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + const struct adi_pinctrl_soc_data *soc; +}; + +/** + * struct gpio_port - GPIO bank device. Multiple ADI GPIO banks can be mapped + * into one pin interrupt controller. + * + * @node: All gpio_port instances are added to a list. + * @base: GPIO bank device register base address + * @irq_base: base IRQ of the GPIO bank device + * @width: PIN number of the GPIO bank device + * @regs: address pointer to the GPIO bank device + * @saved_data: registers that should be saved between PM operations. + * @dev: device structure of this GPIO bank + * @pint: GPIO PINT device that this GPIO bank mapped to + * @pint_map: GIOP bank mapping code in PINT device + * @pint_assign: The 32-bit PINT registers can be divided into 2 parts. A + * GPIO bank can be mapped into either low 16 bits[0] or high 16 + * bits[1] of each PINT register. + * @lock: This lock make sure the irq_chip operations to one PINT device + * for different GPIO interrrupts are atomic. + * @chip: abstract a GPIO controller + * @domain: The irq domain owned by the GPIO port. + * @rsvmap: Reservation map array for each pin in the GPIO bank + */ +struct gpio_port { + struct list_head node; + void __iomem *base; + unsigned int irq_base; + unsigned int width; + struct gpio_port_t *regs; + struct gpio_port_saved saved_data; + struct device *dev; + + struct gpio_pint *pint; + u8 pint_map; + bool pint_assign; + + spinlock_t lock; + struct gpio_chip chip; + struct irq_domain *domain; +}; + +static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin) +{ + return pin - range->pin_base; +} + +static inline u32 hwirq_to_pintbit(struct gpio_port *port, int hwirq) +{ + return port->pint_assign ? BIT(hwirq) << PINT_HI_OFFSET : BIT(hwirq); +} + +static struct gpio_pint *find_gpio_pint(unsigned id) +{ + struct gpio_pint *pint; + int i = 0; + + list_for_each_entry(pint, &adi_pint_list, node) { + if (id == i) + return pint; + i++; + } + + return NULL; +} + +static inline void port_setup(struct gpio_port *port, unsigned offset, + bool use_for_gpio) +{ + struct gpio_port_t *regs = port->regs; + + if (use_for_gpio) + writew(readw(®s->port_fer) & ~BIT(offset), + ®s->port_fer); + else + writew(readw(®s->port_fer) | BIT(offset), ®s->port_fer); +} + +static inline void portmux_setup(struct gpio_port *port, unsigned offset, + unsigned short function) +{ + struct gpio_port_t *regs = port->regs; + u32 pmux; + + pmux = readl(®s->port_mux); + + /* The function field of each pin has 2 consecutive bits in + * the mux register. + */ + pmux &= ~(0x3 << (2 * offset)); + pmux |= (function & 0x3) << (2 * offset); + + writel(pmux, ®s->port_mux); +} + +static inline u16 get_portmux(struct gpio_port *port, unsigned offset) +{ + struct gpio_port_t *regs = port->regs; + u32 pmux = readl(®s->port_mux); + + /* The function field of each pin has 2 consecutive bits in + * the mux register. + */ + return pmux >> (2 * offset) & 0x3; +} + +static void adi_gpio_ack_irq(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs = port->pint->regs; + unsigned pintbit = hwirq_to_pintbit(port, d->hwirq); + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { + if (readl(®s->invert_set) & pintbit) + writel(pintbit, ®s->invert_clear); + else + writel(pintbit, ®s->invert_set); + } + + writel(pintbit, ®s->request); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void adi_gpio_mask_ack_irq(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs = port->pint->regs; + unsigned pintbit = hwirq_to_pintbit(port, d->hwirq); + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { + if (readl(®s->invert_set) & pintbit) + writel(pintbit, ®s->invert_clear); + else + writel(pintbit, ®s->invert_set); + } + + writel(pintbit, ®s->request); + writel(pintbit, ®s->mask_clear); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void adi_gpio_mask_irq(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs = port->pint->regs; + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_clear); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void adi_gpio_unmask_irq(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs = port->pint->regs; + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_set); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); +} + +static unsigned int adi_gpio_irq_startup(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs; + + if (!port) { + pr_err("GPIO IRQ %d :Not exist\n", d->irq); + return -ENODEV; + } + + regs = port->pint->regs; + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + port_setup(port, d->hwirq, true); + writew(BIT(d->hwirq), &port->regs->dir_clear); + writew(readw(&port->regs->inen) | BIT(d->hwirq), &port->regs->inen); + + writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_set); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void adi_gpio_irq_shutdown(struct irq_data *d) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *regs = port->pint->regs; + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_clear); + + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int adi_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + unsigned long flags; + struct gpio_port *port = irq_data_get_irq_chip_data(d); + struct gpio_pint_regs *pint_regs; + unsigned pintmask; + unsigned int irq = d->irq; + int ret = 0; + char buf[16]; + + if (!port) { + pr_err("GPIO IRQ %d :Not exist\n", d->irq); + return -ENODEV; + } + + pint_regs = port->pint->regs; + + pintmask = hwirq_to_pintbit(port, d->hwirq); + + spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->pint->lock); + + /* In case of interrupt autodetect, set irq type to edge sensitive. */ + if (type == IRQ_TYPE_PROBE) + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + snprintf(buf, 16, "gpio-irq%d", irq); + port_setup(port, d->hwirq, true); + } else + goto out; + + /* The GPIO interrupt is triggered only when its input value + * transfer from 0 to 1. So, invert the input value if the + * irq type is low or falling + */ + if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) + writel(pintmask, &pint_regs->invert_set); + else + writel(pintmask, &pint_regs->invert_clear); + + /* In edge sensitive case, if the input value of the requested irq + * is already 1, invert it. + */ + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + if (gpio_get_value(port->chip.base + d->hwirq)) + writel(pintmask, &pint_regs->invert_set); + else + writel(pintmask, &pint_regs->invert_clear); + } + + if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { + writel(pintmask, &pint_regs->edge_set); + __irq_set_handler_locked(irq, handle_edge_irq); + } else { + writel(pintmask, &pint_regs->edge_clear); + __irq_set_handler_locked(irq, handle_level_irq); + } + +out: + spin_unlock(&port->pint->lock); + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +#ifdef CONFIG_PM +static int adi_gpio_set_wake(struct irq_data *d, unsigned int state) +{ + struct gpio_port *port = irq_data_get_irq_chip_data(d); + + if (!port || !port->pint || port->pint->irq != d->irq) + return -EINVAL; + +#ifndef SEC_GCTL + adi_internal_set_wake(port->pint->irq, state); +#endif + + return 0; +} + +static int adi_pint_suspend(void) +{ + struct gpio_pint *pint; + + list_for_each_entry(pint, &adi_pint_list, node) { + writel(0xffffffff, &pint->regs->mask_clear); + pint->saved_data.assign = readl(&pint->regs->assign); + pint->saved_data.edge_set = readl(&pint->regs->edge_set); + pint->saved_data.invert_set = readl(&pint->regs->invert_set); + } + + return 0; +} + +static void adi_pint_resume(void) +{ + struct gpio_pint *pint; + + list_for_each_entry(pint, &adi_pint_list, node) { + writel(pint->saved_data.assign, &pint->regs->assign); + writel(pint->saved_data.edge_set, &pint->regs->edge_set); + writel(pint->saved_data.invert_set, &pint->regs->invert_set); + } +} + +static int adi_gpio_suspend(void) +{ + struct gpio_port *port; + + list_for_each_entry(port, &adi_gpio_port_list, node) { + port->saved_data.fer = readw(&port->regs->port_fer); + port->saved_data.mux = readl(&port->regs->port_mux); + port->saved_data.data = readw(&port->regs->data); + port->saved_data.inen = readw(&port->regs->inen); + port->saved_data.dir = readw(&port->regs->dir_set); + } + + return adi_pint_suspend(); +} + +static void adi_gpio_resume(void) +{ + struct gpio_port *port; + + adi_pint_resume(); + + list_for_each_entry(port, &adi_gpio_port_list, node) { + writel(port->saved_data.mux, &port->regs->port_mux); + writew(port->saved_data.fer, &port->regs->port_fer); + writew(port->saved_data.inen, &port->regs->inen); + writew(port->saved_data.data & port->saved_data.dir, + &port->regs->data_set); + writew(port->saved_data.dir, &port->regs->dir_set); + } + +} + +static struct syscore_ops gpio_pm_syscore_ops = { + .suspend = adi_gpio_suspend, + .resume = adi_gpio_resume, +}; +#else /* CONFIG_PM */ +#define adi_gpio_set_wake NULL +#endif /* CONFIG_PM */ + +#ifdef CONFIG_IRQ_PREFLOW_FASTEOI +static inline void preflow_handler(struct irq_desc *desc) +{ + if (desc->preflow_handler) + desc->preflow_handler(&desc->irq_data); +} +#else +static inline void preflow_handler(struct irq_desc *desc) { } +#endif + +static void adi_gpio_handle_pint_irq(unsigned int inta_irq, + struct irq_desc *desc) +{ + u32 request; + u32 level_mask, hwirq; + bool umask = false; + struct gpio_pint *pint = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct gpio_pint_regs *regs = pint->regs; + struct irq_domain *domain; + + preflow_handler(desc); + chained_irq_enter(chip, desc); + + request = readl(®s->request); + level_mask = readl(®s->edge_set) & request; + + hwirq = 0; + domain = pint->domain[0]; + while (request) { + /* domain pointer need to be changed only once at IRQ 16 when + * we go through IRQ requests from bit 0 to bit 31. + */ + if (hwirq == PINT_HI_OFFSET) + domain = pint->domain[1]; + + if (request & 1) { + if (level_mask & BIT(hwirq)) { + umask = true; + chained_irq_exit(chip, desc); + } + generic_handle_irq(irq_find_mapping(domain, + hwirq % PINT_HI_OFFSET)); + } + + hwirq++; + request >>= 1; + } + + if (!umask) + chained_irq_exit(chip, desc); +} + +static struct irq_chip adi_gpio_irqchip = { + .name = "GPIO", + .irq_ack = adi_gpio_ack_irq, + .irq_mask = adi_gpio_mask_irq, + .irq_mask_ack = adi_gpio_mask_ack_irq, + .irq_unmask = adi_gpio_unmask_irq, + .irq_disable = adi_gpio_mask_irq, + .irq_enable = adi_gpio_unmask_irq, + .irq_set_type = adi_gpio_irq_type, + .irq_startup = adi_gpio_irq_startup, + .irq_shutdown = adi_gpio_irq_shutdown, + .irq_set_wake = adi_gpio_set_wake, +}; + +static int adi_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->soc->ngroups; +} + +static const char *adi_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->soc->groups[selector].name; +} + +static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = pinctrl->soc->groups[selector].pins; + *num_pins = pinctrl->soc->groups[selector].num; + return 0; +} + +static struct pinctrl_ops adi_pctrl_ops = { + .get_groups_count = adi_get_groups_count, + .get_group_name = adi_get_group_name, + .get_group_pins = adi_get_group_pins, +}; + +static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + struct gpio_port *port; + struct pinctrl_gpio_range *range; + unsigned long flags; + unsigned short *mux, pin; + + mux = (unsigned short *)pinctrl->soc->functions[selector].mux; + + while (*mux) { + pin = P_IDENT(*mux); + + range = pinctrl_find_gpio_range_from_pin(pctldev, pin); + if (range == NULL) /* should not happen */ + return -ENODEV; + + port = container_of(range->gc, struct gpio_port, chip); + + spin_lock_irqsave(&port->lock, flags); + + portmux_setup(port, pin_to_offset(range, pin), + P_FUNCT2MUX(*mux)); + port_setup(port, pin_to_offset(range, pin), false); + mux++; + + spin_unlock_irqrestore(&port->lock, flags); + } + + return 0; +} + +static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + struct gpio_port *port; + struct pinctrl_gpio_range *range; + unsigned long flags; + unsigned short *mux, pin; + + mux = (unsigned short *)pinctrl->soc->functions[selector].mux; + + while (*mux) { + pin = P_IDENT(*mux); + + range = pinctrl_find_gpio_range_from_pin(pctldev, pin); + if (range == NULL) /* should not happen */ + return; + + port = container_of(range->gc, struct gpio_port, chip); + + spin_lock_irqsave(&port->lock, flags); + + port_setup(port, pin_to_offset(range, pin), true); + mux++; + + spin_unlock_irqrestore(&port->lock, flags); + } +} + +static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->soc->nfunctions; +} + +static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return pinctrl->soc->functions[selector].name; +} + +static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pinctrl->soc->functions[selector].groups; + *num_groups = pinctrl->soc->functions[selector].num_groups; + return 0; +} + +static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned pin) +{ + struct gpio_port *port; + unsigned long flags; + u8 offset; + + port = container_of(range->gc, struct gpio_port, chip); + offset = pin_to_offset(range, pin); + + spin_lock_irqsave(&port->lock, flags); + + port_setup(port, offset, true); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static struct pinmux_ops adi_pinmux_ops = { + .enable = adi_pinmux_enable, + .disable = adi_pinmux_disable, + .get_functions_count = adi_pinmux_get_funcs_count, + .get_function_name = adi_pinmux_get_func_name, + .get_function_groups = adi_pinmux_get_groups, + .gpio_request_enable = adi_pinmux_request_gpio, +}; + + +static struct pinctrl_desc adi_pinmux_desc = { + .name = DRIVER_NAME, + .pctlops = &adi_pctrl_ops, + .pmxops = &adi_pinmux_ops, + .owner = THIS_MODULE, +}; + +static int adi_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void adi_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_port *port; + unsigned long flags; + + port = container_of(chip, struct gpio_port, chip); + + spin_lock_irqsave(&port->lock, flags); + + writew(BIT(offset), &port->regs->dir_clear); + writew(readw(&port->regs->inen) | BIT(offset), &port->regs->inen); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct gpio_port *port = container_of(chip, struct gpio_port, chip); + struct gpio_port_t *regs = port->regs; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + if (value) + writew(BIT(offset), ®s->data_set); + else + writew(BIT(offset), ®s->data_clear); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct gpio_port *port = container_of(chip, struct gpio_port, chip); + struct gpio_port_t *regs = port->regs; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + writew(readw(®s->inen) & ~BIT(offset), ®s->inen); + if (value) + writew(BIT(offset), ®s->data_set); + else + writew(BIT(offset), ®s->data_clear); + writew(BIT(offset), ®s->dir_set); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_port *port = container_of(chip, struct gpio_port, chip); + struct gpio_port_t *regs = port->regs; + unsigned long flags; + int ret; + + spin_lock_irqsave(&port->lock, flags); + + ret = !!(readw(®s->data) & BIT(offset)); + + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_port *port = container_of(chip, struct gpio_port, chip); + + if (port->irq_base >= 0) + return irq_find_mapping(port->domain, offset); + else + return irq_create_mapping(port->domain, offset); +} + +static int adi_pint_map_port(struct gpio_pint *pint, bool assign, u8 map, + struct irq_domain *domain) +{ + struct gpio_pint_regs *regs = pint->regs; + u32 map_mask; + + if (pint->map_count > 1) + return -EINVAL; + + pint->map_count++; + + /* The map_mask of each gpio port is a 16-bit duplicate + * of the 8-bit map. It can be set to either high 16 bits or low + * 16 bits of the pint assignment register. + */ + map_mask = (map << 8) | map; + if (assign) { + map_mask <<= PINT_HI_OFFSET; + writel((readl(®s->assign) & 0xFFFF) | map_mask, + ®s->assign); + } else + writel((readl(®s->assign) & 0xFFFF0000) | map_mask, + ®s->assign); + + pint->domain[assign] = domain; + + return 0; +} + +static int adi_gpio_pint_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct gpio_pint *pint; + + pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL); + if (!pint) { + dev_err(dev, "Memory alloc failed\n"); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pint->base = devm_ioremap_resource(dev, res); + if (IS_ERR(pint->base)) + return PTR_ERR(pint->base); + + pint->regs = (struct gpio_pint_regs *)pint->base; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "Invalid IRQ resource\n"); + return -ENODEV; + } + + spin_lock_init(&pint->lock); + + pint->irq = res->start; + pint->pint_map_port = adi_pint_map_port; + platform_set_drvdata(pdev, pint); + + irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq); + irq_set_handler_data(pint->irq, pint); + + list_add_tail(&pint->node, &adi_pint_list); + + return 0; +} + +static int adi_gpio_pint_remove(struct platform_device *pdev) +{ + struct gpio_pint *pint = platform_get_drvdata(pdev); + + list_del(&pint->node); + irq_set_handler(pint->irq, handle_simple_irq); + + return 0; +} + +static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gpio_port *port = d->host_data; + + if (!port) + return -EINVAL; + + irq_set_chip_data(irq, port); + irq_set_chip_and_handler(irq, &adi_gpio_irqchip, + handle_level_irq); + + return 0; +} + +const struct irq_domain_ops adi_gpio_irq_domain_ops = { + .map = adi_gpio_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int adi_gpio_init_int(struct gpio_port *port) +{ + struct device_node *node = port->dev->of_node; + struct gpio_pint *pint = port->pint; + int ret; + + port->domain = irq_domain_add_linear(node, port->width, + &adi_gpio_irq_domain_ops, port); + if (!port->domain) { + dev_err(port->dev, "Failed to create irqdomain\n"); + return -ENOSYS; + } + + /* According to BF54x and BF60x HRM, pin interrupt devices are not + * part of the GPIO port device. in GPIO interrupt mode, the GPIO + * pins of multiple port devices can be routed into one pin interrupt + * device. The mapping can be configured by setting pint assignment + * register with the mapping value of different GPIO port. This is + * done via function pint_map_port(). + */ + ret = pint->pint_map_port(port->pint, port->pint_assign, + port->pint_map, port->domain); + if (ret) + return ret; + + if (port->irq_base >= 0) { + ret = irq_create_strict_mappings(port->domain, port->irq_base, + 0, port->width); + if (ret) { + dev_err(port->dev, "Couldn't associate to domain\n"); + return ret; + } + } + + return 0; +} + +#define DEVNAME_SIZE 16 + +static int adi_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct adi_pinctrl_gpio_platform_data *pdata; + struct resource *res; + struct gpio_port *port; + char pinctrl_devname[DEVNAME_SIZE]; + static int gpio; + int ret = 0, ret1; + + pdata = dev->platform_data; + if (!pdata) + return -EINVAL; + + port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL); + if (!port) { + dev_err(dev, "Memory alloc failed\n"); + return -ENOMEM; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->base = devm_ioremap_resource(dev, res); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) + port->irq_base = -1; + else + port->irq_base = res->start; + + port->width = pdata->port_width; + port->dev = dev; + port->regs = (struct gpio_port_t *)port->base; + port->pint_assign = pdata->pint_assign; + port->pint_map = pdata->pint_map; + + port->pint = find_gpio_pint(pdata->pint_id); + if (port->pint) { + ret = adi_gpio_init_int(port); + if (ret) + return ret; + } + + spin_lock_init(&port->lock); + + platform_set_drvdata(pdev, port); + + port->chip.label = "adi-gpio"; + port->chip.direction_input = adi_gpio_direction_input; + port->chip.get = adi_gpio_get_value; + port->chip.direction_output = adi_gpio_direction_output; + port->chip.set = adi_gpio_set_value; + port->chip.request = adi_gpio_request; + port->chip.free = adi_gpio_free; + port->chip.to_irq = adi_gpio_to_irq; + if (pdata->port_gpio_base > 0) + port->chip.base = pdata->port_gpio_base; + else + port->chip.base = gpio; + port->chip.ngpio = port->width; + gpio = port->chip.base + port->width; + + ret = gpiochip_add(&port->chip); + if (ret) { + dev_err(&pdev->dev, "Fail to add GPIO chip.\n"); + goto out_remove_domain; + } + + /* Add gpio pin range */ + snprintf(pinctrl_devname, DEVNAME_SIZE, "pinctrl-adi2.%d", + pdata->pinctrl_id); + pinctrl_devname[DEVNAME_SIZE - 1] = 0; + ret = gpiochip_add_pin_range(&port->chip, pinctrl_devname, + 0, pdata->port_pin_base, port->width); + if (ret) { + dev_err(&pdev->dev, "Fail to add pin range to %s.\n", + pinctrl_devname); + goto out_remove_gpiochip; + } + + list_add_tail(&port->node, &adi_gpio_port_list); + + return 0; + +out_remove_gpiochip: + ret1 = gpiochip_remove(&port->chip); +out_remove_domain: + if (port->pint) + irq_domain_remove(port->domain); + + return ret; +} + +static int adi_gpio_remove(struct platform_device *pdev) +{ + struct gpio_port *port = platform_get_drvdata(pdev); + int ret; + u8 offset; + + list_del(&port->node); + gpiochip_remove_pin_ranges(&port->chip); + ret = gpiochip_remove(&port->chip); + if (port->pint) { + for (offset = 0; offset < port->width; offset++) + irq_dispose_mapping(irq_find_mapping(port->domain, + offset)); + irq_domain_remove(port->domain); + } + + return ret; +} + +static int adi_pinctrl_probe(struct platform_device *pdev) +{ + struct adi_pinctrl *pinctrl; + + pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL); + if (!pinctrl) + return -ENOMEM; + + pinctrl->dev = &pdev->dev; + + adi_pinctrl_soc_init(&pinctrl->soc); + + adi_pinmux_desc.pins = pinctrl->soc->pins; + adi_pinmux_desc.npins = pinctrl->soc->npins; + + /* Now register the pin controller and all pins it handles */ + pinctrl->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pinctrl); + if (!pinctrl->pctl) { + dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n"); + return -EINVAL; + } + + platform_set_drvdata(pdev, pinctrl); + + return 0; +} + +static int adi_pinctrl_remove(struct platform_device *pdev) +{ + struct adi_pinctrl *pinctrl = platform_get_drvdata(pdev); + + pinctrl_unregister(pinctrl->pctl); + + return 0; +} + +static struct platform_driver adi_pinctrl_driver = { + .probe = adi_pinctrl_probe, + .remove = adi_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static struct platform_driver adi_gpio_pint_driver = { + .probe = adi_gpio_pint_probe, + .remove = adi_gpio_pint_remove, + .driver = { + .name = "adi-gpio-pint", + }, +}; + +static struct platform_driver adi_gpio_driver = { + .probe = adi_gpio_probe, + .remove = adi_gpio_remove, + .driver = { + .name = "adi-gpio", + }, +}; + +static int __init adi_pinctrl_setup(void) +{ + int ret; + + ret = platform_driver_register(&adi_pinctrl_driver); + if (ret) + return ret; + + ret = platform_driver_register(&adi_gpio_pint_driver); + if (ret) + goto pint_error; + + ret = platform_driver_register(&adi_gpio_driver); + if (ret) + goto gpio_error; + +#ifdef CONFIG_PM + register_syscore_ops(&gpio_pm_syscore_ops); +#endif + return ret; +gpio_error: + platform_driver_unregister(&adi_gpio_pint_driver); +pint_error: + platform_driver_unregister(&adi_pinctrl_driver); + + return ret; +} +arch_initcall(adi_pinctrl_setup); + +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); +MODULE_DESCRIPTION("ADI gpio2 pin control driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-adi2.h b/drivers/pinctrl/pinctrl-adi2.h new file mode 100644 index 00000000000..1f06f8df1fa --- /dev/null +++ b/drivers/pinctrl/pinctrl-adi2.h @@ -0,0 +1,75 @@ +/* + * Pinctrl Driver for ADI GPIO2 controller + * + * Copyright 2007-2013 Analog Devices Inc. + * + * Licensed under the GPLv2 or later + */ + +#ifndef PINCTRL_PINCTRL_ADI2_H +#define PINCTRL_PINCTRL_ADI2_H + +#include <linux/pinctrl/pinctrl.h> + + /** + * struct adi_pin_group - describes a pin group + * @name: the name of this pin group + * @pins: an array of pins + * @num: the number of pins in this array + */ +struct adi_pin_group { + const char *name; + const unsigned *pins; + const unsigned num; +}; + +#define ADI_PIN_GROUP(n, p) \ + { \ + .name = n, \ + .pins = p, \ + .num = ARRAY_SIZE(p), \ + } + + /** + * struct adi_pmx_func - describes function mux setting of pin groups + * @name: the name of this function mux setting + * @groups: an array of pin groups + * @num_groups: the number of pin groups in this array + * @mux: the function mux setting array, end by zero + */ +struct adi_pmx_func { + const char *name; + const char * const *groups; + const unsigned num_groups; + const unsigned short *mux; +}; + +#define ADI_PMX_FUNCTION(n, g, m) \ + { \ + .name = n, \ + .groups = g, \ + .num_groups = ARRAY_SIZE(g), \ + .mux = m, \ + } + +/** + * struct adi_pinctrl_soc_data - ADI pin controller per-SoC configuration + * @functions: The functions supported on this SoC. + * @nfunction: The number of entries in @functions. + * @groups: An array describing all pin groups the pin SoC supports. + * @ngroups: The number of entries in @groups. + * @pins: An array describing all pins the pin controller affects. + * @npins: The number of entries in @pins. + */ +struct adi_pinctrl_soc_data { + const struct adi_pmx_func *functions; + int nfunctions; + const struct adi_pin_group *groups; + int ngroups; + const struct pinctrl_pin_desc *pins; + int npins; +}; + +void adi_pinctrl_soc_init(const struct adi_pinctrl_soc_data **soc); + +#endif /* PINCTRL_PINCTRL_ADI2_H */ diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c new file mode 100644 index 00000000000..01bffc1d52f --- /dev/null +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -0,0 +1,630 @@ +/* + * ams AS3722 pin control and GPIO driver. + * + * Copyright (c) 2013, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#include "core.h" +#include "pinconf.h" +#include "pinctrl-utils.h" + +#define AS3722_PIN_GPIO0 0 +#define AS3722_PIN_GPIO1 1 +#define AS3722_PIN_GPIO2 2 +#define AS3722_PIN_GPIO3 3 +#define AS3722_PIN_GPIO4 4 +#define AS3722_PIN_GPIO5 5 +#define AS3722_PIN_GPIO6 6 +#define AS3722_PIN_GPIO7 7 +#define AS3722_PIN_NUM (AS3722_PIN_GPIO7 + 1) + +#define AS3722_GPIO_MODE_PULL_UP BIT(PIN_CONFIG_BIAS_PULL_UP) +#define AS3722_GPIO_MODE_PULL_DOWN BIT(PIN_CONFIG_BIAS_PULL_DOWN) +#define AS3722_GPIO_MODE_HIGH_IMPED BIT(PIN_CONFIG_BIAS_HIGH_IMPEDANCE) +#define AS3722_GPIO_MODE_OPEN_DRAIN BIT(PIN_CONFIG_DRIVE_OPEN_DRAIN) + +struct as3722_pin_function { + const char *name; + const char * const *groups; + unsigned ngroups; + int mux_option; +}; + +struct as3722_gpio_pin_control { + bool enable_gpio_invert; + unsigned mode_prop; + int io_function; +}; + +struct as3722_pingroup { + const char *name; + const unsigned pins[1]; + unsigned npins; +}; + +struct as3722_pctrl_info { + struct device *dev; + struct pinctrl_dev *pctl; + struct as3722 *as3722; + struct gpio_chip gpio_chip; + int pins_current_opt[AS3722_PIN_NUM]; + const struct as3722_pin_function *functions; + unsigned num_functions; + const struct as3722_pingroup *pin_groups; + int num_pin_groups; + const struct pinctrl_pin_desc *pins; + unsigned num_pins; + struct as3722_gpio_pin_control gpio_control[AS3722_PIN_NUM]; +}; + +static const struct pinctrl_pin_desc as3722_pins_desc[] = { + PINCTRL_PIN(AS3722_PIN_GPIO0, "gpio0"), + PINCTRL_PIN(AS3722_PIN_GPIO1, "gpio1"), + PINCTRL_PIN(AS3722_PIN_GPIO2, "gpio2"), + PINCTRL_PIN(AS3722_PIN_GPIO3, "gpio3"), + PINCTRL_PIN(AS3722_PIN_GPIO4, "gpio4"), + PINCTRL_PIN(AS3722_PIN_GPIO5, "gpio5"), + PINCTRL_PIN(AS3722_PIN_GPIO6, "gpio6"), + PINCTRL_PIN(AS3722_PIN_GPIO7, "gpio7"), +}; + +static const char * const gpio_groups[] = { + "gpio0", + "gpio1", + "gpio2", + "gpio3", + "gpio4", + "gpio5", + "gpio6", + "gpio7", +}; + +enum as3722_pinmux_option { + AS3722_PINMUX_GPIO = 0, + AS3722_PINMUX_INTERRUPT_OUT = 1, + AS3722_PINMUX_VSUB_VBAT_UNDEB_LOW_OUT = 2, + AS3722_PINMUX_GPIO_INTERRUPT = 3, + AS3722_PINMUX_PWM_INPUT = 4, + AS3722_PINMUX_VOLTAGE_IN_STBY = 5, + AS3722_PINMUX_OC_PG_SD0 = 6, + AS3722_PINMUX_PG_OUT = 7, + AS3722_PINMUX_CLK32K_OUT = 8, + AS3722_PINMUX_WATCHDOG_INPUT = 9, + AS3722_PINMUX_SOFT_RESET_IN = 11, + AS3722_PINMUX_PWM_OUTPUT = 12, + AS3722_PINMUX_VSUB_VBAT_LOW_DEB_OUT = 13, + AS3722_PINMUX_OC_PG_SD6 = 14, +}; + +#define FUNCTION_GROUP(fname, mux) \ + { \ + .name = #fname, \ + .groups = gpio_groups, \ + .ngroups = ARRAY_SIZE(gpio_groups), \ + .mux_option = AS3722_PINMUX_##mux, \ + } + +static const struct as3722_pin_function as3722_pin_function[] = { + FUNCTION_GROUP(gpio, GPIO), + FUNCTION_GROUP(interrupt-out, INTERRUPT_OUT), + FUNCTION_GROUP(gpio-in-interrupt, GPIO_INTERRUPT), + FUNCTION_GROUP(vsup-vbat-low-undebounce-out, VSUB_VBAT_UNDEB_LOW_OUT), + FUNCTION_GROUP(vsup-vbat-low-debounce-out, VSUB_VBAT_LOW_DEB_OUT), + FUNCTION_GROUP(voltage-in-standby, VOLTAGE_IN_STBY), + FUNCTION_GROUP(oc-pg-sd0, OC_PG_SD0), + FUNCTION_GROUP(oc-pg-sd6, OC_PG_SD6), + FUNCTION_GROUP(powergood-out, PG_OUT), + FUNCTION_GROUP(pwm-in, PWM_INPUT), + FUNCTION_GROUP(pwm-out, PWM_OUTPUT), + FUNCTION_GROUP(clk32k-out, CLK32K_OUT), + FUNCTION_GROUP(watchdog-in, WATCHDOG_INPUT), + FUNCTION_GROUP(soft-reset-in, SOFT_RESET_IN), +}; + +#define AS3722_PINGROUP(pg_name, pin_id) \ + { \ + .name = #pg_name, \ + .pins = {AS3722_PIN_##pin_id}, \ + .npins = 1, \ + } + +static const struct as3722_pingroup as3722_pingroups[] = { + AS3722_PINGROUP(gpio0, GPIO0), + AS3722_PINGROUP(gpio1, GPIO1), + AS3722_PINGROUP(gpio2, GPIO2), + AS3722_PINGROUP(gpio3, GPIO3), + AS3722_PINGROUP(gpio4, GPIO4), + AS3722_PINGROUP(gpio5, GPIO5), + AS3722_PINGROUP(gpio6, GPIO6), + AS3722_PINGROUP(gpio7, GPIO7), +}; + +static int as3722_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + return as_pci->num_pin_groups; +} + +static const char *as3722_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + return as_pci->pin_groups[group].name; +} + +static int as3722_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, const unsigned **pins, unsigned *num_pins) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + *pins = as_pci->pin_groups[group].pins; + *num_pins = as_pci->pin_groups[group].npins; + return 0; +} + +static const struct pinctrl_ops as3722_pinctrl_ops = { + .get_groups_count = as3722_pinctrl_get_groups_count, + .get_group_name = as3722_pinctrl_get_group_name, + .get_group_pins = as3722_pinctrl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int as3722_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + return as_pci->num_functions; +} + +static const char *as3722_pinctrl_get_func_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + return as_pci->functions[function].name; +} + +static int as3722_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, + unsigned function, const char * const **groups, + unsigned * const num_groups) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + *groups = as_pci->functions[function].groups; + *num_groups = as_pci->functions[function].ngroups; + return 0; +} + +static int as3722_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, + unsigned group) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + int gpio_cntr_reg = AS3722_GPIOn_CONTROL_REG(group); + u8 val = AS3722_GPIO_IOSF_VAL(as_pci->functions[function].mux_option); + int ret; + + dev_dbg(as_pci->dev, "%s(): GPIO %u pin to function %u and val %u\n", + __func__, group, function, val); + + ret = as3722_update_bits(as_pci->as3722, gpio_cntr_reg, + AS3722_GPIO_IOSF_MASK, val); + if (ret < 0) { + dev_err(as_pci->dev, "GPIO%d_CTRL_REG update failed %d\n", + group, ret); + return ret; + } + as_pci->gpio_control[group].io_function = function; + return ret; +} + +static int as3722_pinctrl_gpio_get_mode(unsigned gpio_mode_prop, bool input) +{ + if (gpio_mode_prop & AS3722_GPIO_MODE_HIGH_IMPED) + return -EINVAL; + + if (gpio_mode_prop & AS3722_GPIO_MODE_OPEN_DRAIN) { + if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP) + return AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP; + return AS3722_GPIO_MODE_IO_OPEN_DRAIN; + } + if (input) { + if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP) + return AS3722_GPIO_MODE_INPUT_PULL_UP; + else if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN) + return AS3722_GPIO_MODE_INPUT_PULL_DOWN; + return AS3722_GPIO_MODE_INPUT; + } + if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN) + return AS3722_GPIO_MODE_OUTPUT_VDDL; + return AS3722_GPIO_MODE_OUTPUT_VDDH; +} + +static int as3722_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + + if (as_pci->gpio_control[offset].io_function) + return -EBUSY; + return 0; +} + +static int as3722_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + struct as3722 *as3722 = as_pci->as3722; + int mode; + + mode = as3722_pinctrl_gpio_get_mode( + as_pci->gpio_control[offset].mode_prop, input); + if (mode < 0) { + dev_err(as_pci->dev, "%s direction for GPIO %d not supported\n", + (input) ? "Input" : "Output", offset); + return mode; + } + + if (as_pci->gpio_control[offset].enable_gpio_invert) + mode |= AS3722_GPIO_INV; + + return as3722_write(as3722, AS3722_GPIOn_CONTROL_REG(offset), mode); +} + +static const struct pinmux_ops as3722_pinmux_ops = { + .get_functions_count = as3722_pinctrl_get_funcs_count, + .get_function_name = as3722_pinctrl_get_func_name, + .get_function_groups = as3722_pinctrl_get_func_groups, + .enable = as3722_pinctrl_enable, + .gpio_request_enable = as3722_pinctrl_gpio_request_enable, + .gpio_set_direction = as3722_pinctrl_gpio_set_direction, +}; + +static int as3722_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long *config) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + int arg = 0; + u16 prop; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + prop = AS3722_GPIO_MODE_PULL_UP | + AS3722_GPIO_MODE_PULL_DOWN; + if (!(as_pci->gpio_control[pin].mode_prop & prop)) + arg = 1; + prop = 0; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + prop = AS3722_GPIO_MODE_PULL_UP; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + prop = AS3722_GPIO_MODE_PULL_DOWN; + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + prop = AS3722_GPIO_MODE_OPEN_DRAIN; + break; + + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + prop = AS3722_GPIO_MODE_HIGH_IMPED; + break; + + default: + dev_err(as_pci->dev, "Properties not supported\n"); + return -ENOTSUPP; + } + + if (as_pci->gpio_control[pin].mode_prop & prop) + arg = 1; + + *config = pinconf_to_config_packed(param, (u16)arg); + return 0; +} + +static int as3722_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin, unsigned long *configs, + unsigned num_configs) +{ + struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param; + int mode_prop; + int i; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + mode_prop = as_pci->gpio_control[pin].mode_prop; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + break; + + case PIN_CONFIG_BIAS_DISABLE: + mode_prop &= ~(AS3722_GPIO_MODE_PULL_UP | + AS3722_GPIO_MODE_PULL_DOWN); + break; + case PIN_CONFIG_BIAS_PULL_UP: + mode_prop |= AS3722_GPIO_MODE_PULL_UP; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + mode_prop |= AS3722_GPIO_MODE_PULL_DOWN; + break; + + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + mode_prop |= AS3722_GPIO_MODE_HIGH_IMPED; + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + mode_prop |= AS3722_GPIO_MODE_OPEN_DRAIN; + break; + + default: + dev_err(as_pci->dev, "Properties not supported\n"); + return -ENOTSUPP; + } + + as_pci->gpio_control[pin].mode_prop = mode_prop; + } + return 0; +} + +static const struct pinconf_ops as3722_pinconf_ops = { + .pin_config_get = as3722_pinconf_get, + .pin_config_set = as3722_pinconf_set, +}; + +static struct pinctrl_desc as3722_pinctrl_desc = { + .pctlops = &as3722_pinctrl_ops, + .pmxops = &as3722_pinmux_ops, + .confops = &as3722_pinconf_ops, + .owner = THIS_MODULE, +}; + +static inline struct as3722_pctrl_info *to_as_pci(struct gpio_chip *chip) +{ + return container_of(chip, struct as3722_pctrl_info, gpio_chip); +} + +static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct as3722_pctrl_info *as_pci = to_as_pci(chip); + struct as3722 *as3722 = as_pci->as3722; + int ret; + u32 reg; + u32 control; + u32 val; + int mode; + int invert_enable; + + ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &control); + if (ret < 0) { + dev_err(as_pci->dev, + "GPIO_CONTROL%d_REG read failed: %d\n", offset, ret); + return ret; + } + + invert_enable = !!(control & AS3722_GPIO_INV); + mode = control & AS3722_GPIO_MODE_MASK; + switch (mode) { + case AS3722_GPIO_MODE_INPUT: + case AS3722_GPIO_MODE_INPUT_PULL_UP: + case AS3722_GPIO_MODE_INPUT_PULL_DOWN: + case AS3722_GPIO_MODE_IO_OPEN_DRAIN: + case AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP: + reg = AS3722_GPIO_SIGNAL_IN_REG; + break; + case AS3722_GPIO_MODE_OUTPUT_VDDH: + case AS3722_GPIO_MODE_OUTPUT_VDDL: + reg = AS3722_GPIO_SIGNAL_OUT_REG; + break; + default: + return -EINVAL; + } + + ret = as3722_read(as3722, reg, &val); + if (ret < 0) { + dev_err(as_pci->dev, + "GPIO_SIGNAL_IN_REG read failed: %d\n", ret); + return ret; + } + + val = !!(val & AS3722_GPIOn_SIGNAL(offset)); + return (invert_enable) ? !val : val; +} + +static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct as3722_pctrl_info *as_pci = to_as_pci(chip); + struct as3722 *as3722 = as_pci->as3722; + int en_invert = as_pci->gpio_control[offset].enable_gpio_invert; + u32 val; + int ret; + + if (value) + val = (en_invert) ? 0 : AS3722_GPIOn_SIGNAL(offset); + else + val = (en_invert) ? AS3722_GPIOn_SIGNAL(offset) : 0; + + ret = as3722_update_bits(as3722, AS3722_GPIO_SIGNAL_OUT_REG, + AS3722_GPIOn_SIGNAL(offset), val); + if (ret < 0) + dev_err(as_pci->dev, + "GPIO_SIGNAL_OUT_REG update failed: %d\n", ret); +} + +static int as3722_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_gpio_direction_input(chip->base + offset); +} + +static int as3722_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + as3722_gpio_set(chip, offset, value); + return pinctrl_gpio_direction_output(chip->base + offset); +} + +static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct as3722_pctrl_info *as_pci = to_as_pci(chip); + + return as3722_irq_get_virq(as_pci->as3722, offset); +} + +static int as3722_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(chip->base + offset); +} + +static void as3722_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(chip->base + offset); +} + +static const struct gpio_chip as3722_gpio_chip = { + .label = "as3722-gpio", + .owner = THIS_MODULE, + .request = as3722_gpio_request, + .free = as3722_gpio_free, + .get = as3722_gpio_get, + .set = as3722_gpio_set, + .direction_input = as3722_gpio_direction_input, + .direction_output = as3722_gpio_direction_output, + .to_irq = as3722_gpio_to_irq, + .can_sleep = 1, + .ngpio = AS3722_PIN_NUM, + .base = -1, +}; + +static int as3722_pinctrl_probe(struct platform_device *pdev) +{ + struct as3722_pctrl_info *as_pci; + int ret; + int tret; + + as_pci = devm_kzalloc(&pdev->dev, sizeof(*as_pci), GFP_KERNEL); + if (!as_pci) + return -ENOMEM; + + as_pci->dev = &pdev->dev; + as_pci->dev->of_node = pdev->dev.parent->of_node; + as_pci->as3722 = dev_get_drvdata(pdev->dev.parent); + platform_set_drvdata(pdev, as_pci); + + as_pci->pins = as3722_pins_desc; + as_pci->num_pins = ARRAY_SIZE(as3722_pins_desc); + as_pci->functions = as3722_pin_function; + as_pci->num_functions = ARRAY_SIZE(as3722_pin_function); + as_pci->pin_groups = as3722_pingroups; + as_pci->num_pin_groups = ARRAY_SIZE(as3722_pingroups); + as3722_pinctrl_desc.name = dev_name(&pdev->dev); + as3722_pinctrl_desc.pins = as3722_pins_desc; + as3722_pinctrl_desc.npins = ARRAY_SIZE(as3722_pins_desc); + as_pci->pctl = pinctrl_register(&as3722_pinctrl_desc, + &pdev->dev, as_pci); + if (!as_pci->pctl) { + dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); + return -EINVAL; + } + + as_pci->gpio_chip = as3722_gpio_chip; + as_pci->gpio_chip.dev = &pdev->dev; + as_pci->gpio_chip.of_node = pdev->dev.parent->of_node; + ret = gpiochip_add(&as_pci->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret); + goto fail_chip_add; + } + + ret = gpiochip_add_pin_range(&as_pci->gpio_chip, dev_name(&pdev->dev), + 0, 0, AS3722_PIN_NUM); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't add pin range, %d\n", ret); + goto fail_range_add; + } + + return 0; + +fail_range_add: + tret = gpiochip_remove(&as_pci->gpio_chip); + if (tret < 0) + dev_warn(&pdev->dev, "Couldn't remove gpio chip, %d\n", tret); + +fail_chip_add: + pinctrl_unregister(as_pci->pctl); + return ret; +} + +static int as3722_pinctrl_remove(struct platform_device *pdev) +{ + struct as3722_pctrl_info *as_pci = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&as_pci->gpio_chip); + if (ret < 0) + return ret; + pinctrl_unregister(as_pci->pctl); + return 0; +} + +static struct of_device_id as3722_pinctrl_of_match[] = { + { .compatible = "ams,as3722-pinctrl", }, + { }, +}; +MODULE_DEVICE_TABLE(of, as3722_pinctrl_of_match); + +static struct platform_driver as3722_pinctrl_driver = { + .driver = { + .name = "as3722-pinctrl", + .owner = THIS_MODULE, + .of_match_table = as3722_pinctrl_of_match, + }, + .probe = as3722_pinctrl_probe, + .remove = as3722_pinctrl_remove, +}; +module_platform_driver(as3722_pinctrl_driver); + +MODULE_ALIAS("platform:as3722-pinctrl"); +MODULE_DESCRIPTION("AS3722 pin control and GPIO driver"); +MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index f350fd2e170..a7549c4c83b 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -33,6 +33,7 @@ #include "core.h" +#define MAX_GPIO_BANKS 5 #define MAX_NB_GPIO_PER_BANK 32 struct at91_pinctrl_mux_ops; @@ -144,11 +145,11 @@ struct at91_pinctrl_mux_ops { void (*mux_C_periph)(void __iomem *pio, unsigned mask); void (*mux_D_periph)(void __iomem *pio, unsigned mask); bool (*get_deglitch)(void __iomem *pio, unsigned pin); - void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on); + void (*set_deglitch)(void __iomem *pio, unsigned mask, bool is_on); bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); - void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div); + void (*set_debounce)(void __iomem *pio, unsigned mask, bool is_on, u32 div); bool (*get_pulldown)(void __iomem *pio, unsigned pin); - void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on); + void (*set_pulldown)(void __iomem *pio, unsigned mask, bool is_on); bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask); /* irq */ @@ -243,7 +244,7 @@ static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, int i; /* - * first find the group of this node and check if we need create + * first find the group of this node and check if we need to create * config maps for pins */ grp = at91_pinctrl_find_group_by_name(info, np->name); @@ -417,6 +418,14 @@ static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); } +static bool at91_mux_pio3_get_deglitch(void __iomem *pio, unsigned pin) +{ + if ((__raw_readl(pio + PIO_IFSR) >> pin) & 0x1) + return !((__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1); + + return false; +} + static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) { if (is_on) @@ -428,7 +437,8 @@ static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div { *div = __raw_readl(pio + PIO_SCDR); - return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1; + return ((__raw_readl(pio + PIO_IFSR) >> pin) & 0x1) && + ((__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1); } static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, @@ -438,9 +448,8 @@ static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, __raw_writel(mask, pio + PIO_IFSCER); __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); __raw_writel(mask, pio + PIO_IFER); - } else { - __raw_writel(mask, pio + PIO_IFDR); - } + } else + __raw_writel(mask, pio + PIO_IFSCDR); } static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) @@ -478,7 +487,7 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { .mux_B_periph = at91_mux_pio3_set_B_periph, .mux_C_periph = at91_mux_pio3_set_C_periph, .mux_D_periph = at91_mux_pio3_set_D_periph, - .get_deglitch = at91_mux_get_deglitch, + .get_deglitch = at91_mux_pio3_get_deglitch, .set_deglitch = at91_mux_pio3_set_deglitch, .get_debounce = at91_mux_pio3_get_debounce, .set_debounce = at91_mux_pio3_set_debounce, @@ -564,7 +573,7 @@ static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, info->functions[selector].name, info->groups[group].name); /* first check that all the pins of the group are valid with a valid - * paramter */ + * parameter */ for (i = 0; i < npins; i++) { pin = &pins_conf[i]; ret = pin_check_config(info, info->groups[group].name, i, pin); @@ -958,7 +967,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev, at91_pinctrl_child_count(info, np); if (info->nbanks < 1) { - dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n"); + dev_err(&pdev->dev, "you need to specify at least one gpio-controller\n"); return -EINVAL; } @@ -1495,7 +1504,7 @@ static int at91_gpio_of_irq_setup(struct device_node *node, if (at91_gpio->pioc_idx) prev = gpio_chips[at91_gpio->pioc_idx - 1]; - /* The toplevel handler handles one bank of GPIOs, except + /* The top level handler handles one bank of GPIOs, except * on some SoC it can handles up to three... * We only set up the handler for the first of the list. */ @@ -1671,7 +1680,7 @@ static struct platform_driver at91_gpio_driver = { .driver = { .name = "gpio-at91", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(at91_gpio_of_match), + .of_match_table = at91_gpio_of_match, }, .probe = at91_gpio_probe, }; @@ -1680,7 +1689,7 @@ static struct platform_driver at91_pinctrl_driver = { .driver = { .name = "pinctrl-at91", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(at91_pinctrl_of_match), + .of_match_table = at91_pinctrl_of_match, }, .probe = at91_pinctrl_probe, .remove = at91_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index f22a2193d94..162ac0d7373 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -529,6 +529,10 @@ static void u300_gpio_irq_enable(struct irq_data *d) dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", d->hwirq, port->name, offset); + if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) + dev_err(gpio->dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -547,6 +551,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) val = readl(U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); + gpio_unlock_as_irq(&gpio->chip, d->hwirq); } static struct irq_chip u300_gpio_irqchip = { diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c index 544d469c5a7..8fe2ab0a769 100644 --- a/drivers/pinctrl/pinctrl-exynos5440.c +++ b/drivers/pinctrl/pinctrl-exynos5440.c @@ -1048,7 +1048,7 @@ static struct platform_driver exynos5440_pinctrl_driver = { .driver = { .name = "exynos5440-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(exynos5440_pinctrl_dt_match), + .of_match_table = exynos5440_pinctrl_dt_match, }, }; diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index d78dd813bff..4779b8e0eee 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -245,11 +245,11 @@ static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, * The input_reg[i] here is actually some IOMUXC general * purpose register, not regular select input register. */ - val = readl(ipctl->base + pin->input_val); + val = readl(ipctl->base + pin->input_reg); val &= ~mask; val |= select << shift; - writel(val, ipctl->base + pin->input_val); - } else if (pin->input_val) { + writel(val, ipctl->base + pin->input_reg); + } else if (pin->input_reg) { /* * Regular select input register can never be at offset * 0, and we only print register value for regular case. diff --git a/drivers/pinctrl/pinctrl-imx1-core.c b/drivers/pinctrl/pinctrl-imx1-core.c new file mode 100644 index 00000000000..f77914ac081 --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx1-core.c @@ -0,0 +1,653 @@ +/* + * Core driver for the imx pin controller in imx1/21/27 + * + * Copyright (C) 2013 Pengutronix + * Author: Markus Pargmann <mpa@pengutronix.de> + * + * Based on pinctrl-imx.c: + * Author: Dong Aisheng <dong.aisheng@linaro.org> + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/slab.h> + +#include "core.h" +#include "pinctrl-imx1.h" + +struct imx1_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + void __iomem *base; + const struct imx1_pinctrl_soc_info *info; +}; + +/* + * MX1 register offsets + */ + +#define MX1_DDIR 0x00 +#define MX1_OCR 0x04 +#define MX1_ICONFA 0x0c +#define MX1_ICONFB 0x10 +#define MX1_GIUS 0x20 +#define MX1_GPR 0x38 +#define MX1_PUEN 0x40 + +#define MX1_PORT_STRIDE 0x100 + + +/* + * MUX_ID format defines + */ +#define MX1_MUX_FUNCTION(val) (BIT(0) & val) +#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1) +#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2) +#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4) +#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8) +#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10) + + +/* + * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX + * control register are seperated into function, output configuration, input + * configuration A, input configuration B, GPIO in use and data direction. + * + * Those controls that are represented by 1 bit have a direct mapping between + * bit position and pin id. If they are represented by 2 bit, the lower 16 pins + * are in the first register and the upper 16 pins in the second (next) + * register. pin_id is stored in bit (pin_id%16)*2 and the bit above. + */ + +/* + * Calculates the register offset from a pin_id + */ +static void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id) +{ + unsigned int port = pin_id / 32; + return ipctl->base + port * MX1_PORT_STRIDE; +} + +/* + * Write to a register with 2 bits per pin. The function will automatically + * use the next register if the pin is managed in the second register. + */ +static void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, + u32 value, u32 reg_offset) +{ + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; + int offset = (pin_id % 16) * 2; /* offset, regardless of register used */ + int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */ + u32 old_val; + u32 new_val; + + dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", + reg, offset, value); + + /* Use the next register if the pin's port pin number is >=16 */ + if (pin_id % 32 >= 16) + reg += 0x04; + + /* Get current state of pins */ + old_val = readl(reg); + old_val &= mask; + + new_val = value & 0x3; /* Make sure value is really 2 bit */ + new_val <<= offset; + new_val |= old_val;/* Set new state for pin_id */ + + writel(new_val, reg); +} + +static void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, + u32 value, u32 reg_offset) +{ + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; + int offset = pin_id % 32; + int mask = ~BIT_MASK(offset); + u32 old_val; + u32 new_val; + + /* Get current state of pins */ + old_val = readl(reg); + old_val &= mask; + + new_val = value & 0x1; /* Make sure value is really 1 bit */ + new_val <<= offset; + new_val |= old_val;/* Set new state for pin_id */ + + writel(new_val, reg); +} + +static int imx1_read_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, + u32 reg_offset) +{ + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; + int offset = pin_id % 16; + + /* Use the next register if the pin's port pin number is >=16 */ + if (pin_id % 32 >= 16) + reg += 0x04; + + return (readl(reg) & (BIT(offset) | BIT(offset+1))) >> offset; +} + +static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, + u32 reg_offset) +{ + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; + int offset = pin_id % 32; + + return !!(readl(reg) & BIT(offset)); +} + +static const inline struct imx1_pin_group *imx1_pinctrl_find_group_by_name( + const struct imx1_pinctrl_soc_info *info, + const char *name) +{ + const struct imx1_pin_group *grp = NULL; + int i; + + for (i = 0; i < info->ngroups; i++) { + if (!strcmp(info->groups[i].name, name)) { + grp = &info->groups[i]; + break; + } + } + + return grp; +} + +static int imx1_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + return info->ngroups; +} + +static const char *imx1_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + return info->groups[selector].name; +} + +static int imx1_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned int **pins, + unsigned *npins) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pin_ids; + *npins = info->groups[selector].npins; + + return 0; +} + +static void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + seq_printf(s, "GPIO %d, function %d, direction %d, oconf %d, iconfa %d, iconfb %d", + imx1_read_bit(ipctl, offset, MX1_GIUS), + imx1_read_bit(ipctl, offset, MX1_GPR), + imx1_read_bit(ipctl, offset, MX1_DDIR), + imx1_read_2bit(ipctl, offset, MX1_OCR), + imx1_read_2bit(ipctl, offset, MX1_ICONFA), + imx1_read_2bit(ipctl, offset, MX1_ICONFB)); +} + +static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + const struct imx1_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i, j; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = imx1_pinctrl_find_group_by_name(info, np->name); + if (!grp) { + dev_err(info->dev, "unable to find group for node %s\n", + np->name); + return -EINVAL; + } + + for (i = 0; i < grp->npins; i++) + map_num++; + + new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create mux map */ + parent = of_get_parent(np); + if (!parent) { + kfree(new_map); + return -EINVAL; + } + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = j = 0; i < grp->npins; i++) { + new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[j].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[i].pin_id); + new_map[j].data.configs.configs = &grp->pins[i].config; + new_map[j].data.configs.num_configs = 1; + j++; + } + + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, (*map)->data.mux.group, map_num); + + return 0; +} + +static void imx1_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + kfree(map); +} + +static const struct pinctrl_ops imx1_pctrl_ops = { + .get_groups_count = imx1_get_groups_count, + .get_group_name = imx1_get_group_name, + .get_group_pins = imx1_get_group_pins, + .pin_dbg_show = imx1_pin_dbg_show, + .dt_node_to_map = imx1_dt_node_to_map, + .dt_free_map = imx1_dt_free_map, + +}; + +static int imx1_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + const struct imx1_pin *pins; + unsigned int npins; + int i; + + /* + * Configure the mux mode for each pin in the group for a specific + * function. + */ + pins = info->groups[group].pins; + npins = info->groups[group].npins; + + WARN_ON(!pins || !npins); + + dev_dbg(ipctl->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + for (i = 0; i < npins; i++) { + unsigned int mux = pins[i].mux_id; + unsigned int pin_id = pins[i].pin_id; + unsigned int afunction = MX1_MUX_FUNCTION(mux); + unsigned int gpio_in_use = MX1_MUX_GPIO(mux); + unsigned int direction = MX1_MUX_DIR(mux); + unsigned int gpio_oconf = MX1_MUX_OCONF(mux); + unsigned int gpio_iconfa = MX1_MUX_ICONFA(mux); + unsigned int gpio_iconfb = MX1_MUX_ICONFB(mux); + + dev_dbg(pctldev->dev, "%s, pin 0x%x, function %d, gpio %d, direction %d, oconf %d, iconfa %d, iconfb %d\n", + __func__, pin_id, afunction, gpio_in_use, + direction, gpio_oconf, gpio_iconfa, + gpio_iconfb); + + imx1_write_bit(ipctl, pin_id, gpio_in_use, MX1_GIUS); + imx1_write_bit(ipctl, pin_id, direction, MX1_DDIR); + + if (gpio_in_use) { + imx1_write_2bit(ipctl, pin_id, gpio_oconf, MX1_OCR); + imx1_write_2bit(ipctl, pin_id, gpio_iconfa, + MX1_ICONFA); + imx1_write_2bit(ipctl, pin_id, gpio_iconfb, + MX1_ICONFB); + } else { + imx1_write_bit(ipctl, pin_id, afunction, MX1_GPR); + } + } + + return 0; +} + +static int imx1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + return info->nfunctions; +} + +static const char *imx1_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + return info->functions[selector].name; +} + +static int imx1_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].num_groups; + + return 0; +} + +static const struct pinmux_ops imx1_pmx_ops = { + .get_functions_count = imx1_pmx_get_funcs_count, + .get_function_name = imx1_pmx_get_func_name, + .get_function_groups = imx1_pmx_get_groups, + .enable = imx1_pmx_enable, +}; + +static int imx1_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + + *config = imx1_read_bit(ipctl, pin_id, MX1_PUEN); + + return 0; +} + +static int imx1_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *configs, + unsigned num_configs) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + int i; + + for (i = 0; i != num_configs; ++i) { + imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN); + + dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n", + info->pins[pin_id].name); + } + + return 0; +} + +static void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + unsigned long config; + + imx1_pinconf_get(pctldev, pin_id, &config); + seq_printf(s, "0x%lx", config); +} + +static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + const struct imx1_pinctrl_soc_info *info = ipctl->info; + struct imx1_pin_group *grp; + unsigned long config; + const char *name; + int i, ret; + + if (group > info->ngroups) + return; + + seq_puts(s, "\n"); + grp = &info->groups[group]; + for (i = 0; i < grp->npins; i++) { + name = pin_get_name(pctldev, grp->pins[i].pin_id); + ret = imx1_pinconf_get(pctldev, grp->pins[i].pin_id, &config); + if (ret) + return; + seq_printf(s, "%s: 0x%lx", name, config); + } +} + +static const struct pinconf_ops imx1_pinconf_ops = { + .pin_config_get = imx1_pinconf_get, + .pin_config_set = imx1_pinconf_set, + .pin_config_dbg_show = imx1_pinconf_dbg_show, + .pin_config_group_dbg_show = imx1_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc imx1_pinctrl_desc = { + .pctlops = &imx1_pctrl_ops, + .pmxops = &imx1_pmx_ops, + .confops = &imx1_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int imx1_pinctrl_parse_groups(struct device_node *np, + struct imx1_pin_group *grp, + struct imx1_pinctrl_soc_info *info, + u32 index) +{ + int size; + const __be32 *list; + int i; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is fsl,pins = <PIN MUX_ID CONFIG> + */ + list = of_get_property(np, "fsl,pins", &size); + /* we do not check return since it's safe node passed down */ + if (!size || size % 12) { + dev_notice(info->dev, "Not a valid fsl,pins property (%s)\n", + np->name); + return -EINVAL; + } + + grp->npins = size / 12; + grp->pins = devm_kzalloc(info->dev, + grp->npins * sizeof(struct imx1_pin), GFP_KERNEL); + grp->pin_ids = devm_kzalloc(info->dev, + grp->npins * sizeof(unsigned int), GFP_KERNEL); + + if (!grp->pins || !grp->pin_ids) + return -ENOMEM; + + for (i = 0; i < grp->npins; i++) { + grp->pins[i].pin_id = be32_to_cpu(*list++); + grp->pins[i].mux_id = be32_to_cpu(*list++); + grp->pins[i].config = be32_to_cpu(*list++); + + grp->pin_ids[i] = grp->pins[i].pin_id; + } + + return 0; +} + +static int imx1_pinctrl_parse_functions(struct device_node *np, + struct imx1_pinctrl_soc_info *info, + u32 index) +{ + struct device_node *child; + struct imx1_pmx_func *func; + struct imx1_pin_group *grp; + int ret; + static u32 grp_index; + u32 i = 0; + + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->num_groups = of_get_child_count(np); + if (func->num_groups <= 0) + return -EINVAL; + + func->groups = devm_kzalloc(info->dev, + func->num_groups * sizeof(char *), GFP_KERNEL); + + if (!func->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[grp_index++]; + ret = imx1_pinctrl_parse_groups(child, grp, info, i++); + if (ret == -ENOMEM) + return ret; + } + + return 0; +} + +static int imx1_pinctrl_parse_dt(struct platform_device *pdev, + struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + int ret; + u32 nfuncs = 0; + u32 ngroups = 0; + u32 ifunc = 0; + + if (!np) + return -ENODEV; + + for_each_child_of_node(np, child) { + ++nfuncs; + ngroups += of_get_child_count(child); + } + + if (!nfuncs) { + dev_err(&pdev->dev, "No pin functions defined\n"); + return -EINVAL; + } + + info->nfunctions = nfuncs; + info->functions = devm_kzalloc(&pdev->dev, + nfuncs * sizeof(struct imx1_pmx_func), GFP_KERNEL); + + info->ngroups = ngroups; + info->groups = devm_kzalloc(&pdev->dev, + ngroups * sizeof(struct imx1_pin_group), GFP_KERNEL); + + + if (!info->functions || !info->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + ret = imx1_pinctrl_parse_functions(child, info, ifunc++); + if (ret == -ENOMEM) + return -ENOMEM; + } + + return 0; +} + +int imx1_pinctrl_core_probe(struct platform_device *pdev, + struct imx1_pinctrl_soc_info *info) +{ + struct imx1_pinctrl *ipctl; + struct resource *res; + struct pinctrl_desc *pctl_desc; + int ret; + + if (!info || !info->pins || !info->npins) { + dev_err(&pdev->dev, "wrong pinctrl info\n"); + return -EINVAL; + } + info->dev = &pdev->dev; + + /* Create state holders etc for this driver */ + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); + if (!ipctl) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + ipctl->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ipctl->base) + return -ENOMEM; + + pctl_desc = &imx1_pinctrl_desc; + pctl_desc->name = dev_name(&pdev->dev); + pctl_desc->pins = info->pins; + pctl_desc->npins = info->npins; + + ret = imx1_pinctrl_parse_dt(pdev, ipctl, info); + if (ret) { + dev_err(&pdev->dev, "fail to probe dt properties\n"); + return ret; + } + + ipctl->info = info; + ipctl->dev = info->dev; + platform_set_drvdata(pdev, ipctl); + ipctl->pctl = pinctrl_register(pctl_desc, &pdev->dev, ipctl); + if (!ipctl->pctl) { + dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); + return -EINVAL; + } + + dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); + + return 0; +} + +int imx1_pinctrl_core_remove(struct platform_device *pdev) +{ + struct imx1_pinctrl *ipctl = platform_get_drvdata(pdev); + + pinctrl_unregister(ipctl->pctl); + + return 0; +} diff --git a/drivers/pinctrl/pinctrl-imx1.h b/drivers/pinctrl/pinctrl-imx1.h new file mode 100644 index 00000000000..692a54c15cd --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx1.h @@ -0,0 +1,73 @@ +/* + * IMX pinmux core definitions + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng <dong.aisheng@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __DRIVERS_PINCTRL_IMX1_H +#define __DRIVERS_PINCTRL_IMX1_H + +struct platform_device; + +/** + * struct imx1_pin - describes an IMX1/21/27 pin. + * @pin_id: ID of the described pin. + * @mux_id: ID of the mux setup. + * @config: Configuration of the pin (currently only pullup-enable). + */ +struct imx1_pin { + unsigned int pin_id; + unsigned int mux_id; + unsigned long config; +}; + +/** + * struct imx1_pin_group - describes an IMX pin group + * @name: the name of this specific pin group + * @pins: an array of imx1_pin structs used in this group + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + */ +struct imx1_pin_group { + const char *name; + unsigned int *pin_ids; + struct imx1_pin *pins; + unsigned npins; +}; + +/** + * struct imx1_pmx_func - describes IMX pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @num_groups: the number of groups + */ +struct imx1_pmx_func { + const char *name; + const char **groups; + unsigned num_groups; +}; + +struct imx1_pinctrl_soc_info { + struct device *dev; + const struct pinctrl_pin_desc *pins; + unsigned int npins; + struct imx1_pin_group *groups; + unsigned int ngroups; + struct imx1_pmx_func *functions; + unsigned int nfunctions; +}; + +#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) + +int imx1_pinctrl_core_probe(struct platform_device *pdev, + struct imx1_pinctrl_soc_info *info); +int imx1_pinctrl_core_remove(struct platform_device *pdev); +#endif /* __DRIVERS_PINCTRL_IMX1_H */ diff --git a/drivers/pinctrl/pinctrl-imx27.c b/drivers/pinctrl/pinctrl-imx27.c new file mode 100644 index 00000000000..417c99205bc --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx27.c @@ -0,0 +1,477 @@ +/* + * imx27 pinctrl driver based on imx pinmux core + * + * Copyright (C) 2013 Pengutronix + * + * Author: Markus Pargmann <mpa@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-imx1.h" + +#define PAD_ID(port, pin) (port*32 + pin) +#define PA 0 +#define PB 1 +#define PC 2 +#define PD 3 +#define PE 4 +#define PF 5 + +enum imx27_pads { + MX27_PAD_USBH2_CLK = PAD_ID(PA, 0), + MX27_PAD_USBH2_DIR = PAD_ID(PA, 1), + MX27_PAD_USBH2_DATA7 = PAD_ID(PA, 2), + MX27_PAD_USBH2_NXT = PAD_ID(PA, 3), + MX27_PAD_USBH2_STP = PAD_ID(PA, 4), + MX27_PAD_LSCLK = PAD_ID(PA, 5), + MX27_PAD_LD0 = PAD_ID(PA, 6), + MX27_PAD_LD1 = PAD_ID(PA, 7), + MX27_PAD_LD2 = PAD_ID(PA, 8), + MX27_PAD_LD3 = PAD_ID(PA, 9), + MX27_PAD_LD4 = PAD_ID(PA, 10), + MX27_PAD_LD5 = PAD_ID(PA, 11), + MX27_PAD_LD6 = PAD_ID(PA, 12), + MX27_PAD_LD7 = PAD_ID(PA, 13), + MX27_PAD_LD8 = PAD_ID(PA, 14), + MX27_PAD_LD9 = PAD_ID(PA, 15), + MX27_PAD_LD10 = PAD_ID(PA, 16), + MX27_PAD_LD11 = PAD_ID(PA, 17), + MX27_PAD_LD12 = PAD_ID(PA, 18), + MX27_PAD_LD13 = PAD_ID(PA, 19), + MX27_PAD_LD14 = PAD_ID(PA, 20), + MX27_PAD_LD15 = PAD_ID(PA, 21), + MX27_PAD_LD16 = PAD_ID(PA, 22), + MX27_PAD_LD17 = PAD_ID(PA, 23), + MX27_PAD_REV = PAD_ID(PA, 24), + MX27_PAD_CLS = PAD_ID(PA, 25), + MX27_PAD_PS = PAD_ID(PA, 26), + MX27_PAD_SPL_SPR = PAD_ID(PA, 27), + MX27_PAD_HSYNC = PAD_ID(PA, 28), + MX27_PAD_VSYNC = PAD_ID(PA, 29), + MX27_PAD_CONTRAST = PAD_ID(PA, 30), + MX27_PAD_OE_ACD = PAD_ID(PA, 31), + + MX27_PAD_UNUSED0 = PAD_ID(PB, 0), + MX27_PAD_UNUSED1 = PAD_ID(PB, 1), + MX27_PAD_UNUSED2 = PAD_ID(PB, 2), + MX27_PAD_UNUSED3 = PAD_ID(PB, 3), + MX27_PAD_SD2_D0 = PAD_ID(PB, 4), + MX27_PAD_SD2_D1 = PAD_ID(PB, 5), + MX27_PAD_SD2_D2 = PAD_ID(PB, 6), + MX27_PAD_SD2_D3 = PAD_ID(PB, 7), + MX27_PAD_SD2_CMD = PAD_ID(PB, 8), + MX27_PAD_SD2_CLK = PAD_ID(PB, 9), + MX27_PAD_CSI_D0 = PAD_ID(PB, 10), + MX27_PAD_CSI_D1 = PAD_ID(PB, 11), + MX27_PAD_CSI_D2 = PAD_ID(PB, 12), + MX27_PAD_CSI_D3 = PAD_ID(PB, 13), + MX27_PAD_CSI_D4 = PAD_ID(PB, 14), + MX27_PAD_CSI_MCLK = PAD_ID(PB, 15), + MX27_PAD_CSI_PIXCLK = PAD_ID(PB, 16), + MX27_PAD_CSI_D5 = PAD_ID(PB, 17), + MX27_PAD_CSI_D6 = PAD_ID(PB, 18), + MX27_PAD_CSI_D7 = PAD_ID(PB, 19), + MX27_PAD_CSI_VSYNC = PAD_ID(PB, 20), + MX27_PAD_CSI_HSYNC = PAD_ID(PB, 21), + MX27_PAD_USBH1_SUSP = PAD_ID(PB, 22), + MX27_PAD_USB_PWR = PAD_ID(PB, 23), + MX27_PAD_USB_OC_B = PAD_ID(PB, 24), + MX27_PAD_USBH1_RCV = PAD_ID(PB, 25), + MX27_PAD_USBH1_FS = PAD_ID(PB, 26), + MX27_PAD_USBH1_OE_B = PAD_ID(PB, 27), + MX27_PAD_USBH1_TXDM = PAD_ID(PB, 28), + MX27_PAD_USBH1_TXDP = PAD_ID(PB, 29), + MX27_PAD_USBH1_RXDM = PAD_ID(PB, 30), + MX27_PAD_USBH1_RXDP = PAD_ID(PB, 31), + + MX27_PAD_UNUSED4 = PAD_ID(PC, 0), + MX27_PAD_UNUSED5 = PAD_ID(PC, 1), + MX27_PAD_UNUSED6 = PAD_ID(PC, 2), + MX27_PAD_UNUSED7 = PAD_ID(PC, 3), + MX27_PAD_UNUSED8 = PAD_ID(PC, 4), + MX27_PAD_I2C2_SDA = PAD_ID(PC, 5), + MX27_PAD_I2C2_SCL = PAD_ID(PC, 6), + MX27_PAD_USBOTG_DATA5 = PAD_ID(PC, 7), + MX27_PAD_USBOTG_DATA6 = PAD_ID(PC, 8), + MX27_PAD_USBOTG_DATA0 = PAD_ID(PC, 9), + MX27_PAD_USBOTG_DATA2 = PAD_ID(PC, 10), + MX27_PAD_USBOTG_DATA1 = PAD_ID(PC, 11), + MX27_PAD_USBOTG_DATA4 = PAD_ID(PC, 12), + MX27_PAD_USBOTG_DATA3 = PAD_ID(PC, 13), + MX27_PAD_TOUT = PAD_ID(PC, 14), + MX27_PAD_TIN = PAD_ID(PC, 15), + MX27_PAD_SSI4_FS = PAD_ID(PC, 16), + MX27_PAD_SSI4_RXDAT = PAD_ID(PC, 17), + MX27_PAD_SSI4_TXDAT = PAD_ID(PC, 18), + MX27_PAD_SSI4_CLK = PAD_ID(PC, 19), + MX27_PAD_SSI1_FS = PAD_ID(PC, 20), + MX27_PAD_SSI1_RXDAT = PAD_ID(PC, 21), + MX27_PAD_SSI1_TXDAT = PAD_ID(PC, 22), + MX27_PAD_SSI1_CLK = PAD_ID(PC, 23), + MX27_PAD_SSI2_FS = PAD_ID(PC, 24), + MX27_PAD_SSI2_RXDAT = PAD_ID(PC, 25), + MX27_PAD_SSI2_TXDAT = PAD_ID(PC, 26), + MX27_PAD_SSI2_CLK = PAD_ID(PC, 27), + MX27_PAD_SSI3_FS = PAD_ID(PC, 28), + MX27_PAD_SSI3_RXDAT = PAD_ID(PC, 29), + MX27_PAD_SSI3_TXDAT = PAD_ID(PC, 30), + MX27_PAD_SSI3_CLK = PAD_ID(PC, 31), + + MX27_PAD_SD3_CMD = PAD_ID(PD, 0), + MX27_PAD_SD3_CLK = PAD_ID(PD, 1), + MX27_PAD_ATA_DATA0 = PAD_ID(PD, 2), + MX27_PAD_ATA_DATA1 = PAD_ID(PD, 3), + MX27_PAD_ATA_DATA2 = PAD_ID(PD, 4), + MX27_PAD_ATA_DATA3 = PAD_ID(PD, 5), + MX27_PAD_ATA_DATA4 = PAD_ID(PD, 6), + MX27_PAD_ATA_DATA5 = PAD_ID(PD, 7), + MX27_PAD_ATA_DATA6 = PAD_ID(PD, 8), + MX27_PAD_ATA_DATA7 = PAD_ID(PD, 9), + MX27_PAD_ATA_DATA8 = PAD_ID(PD, 10), + MX27_PAD_ATA_DATA9 = PAD_ID(PD, 11), + MX27_PAD_ATA_DATA10 = PAD_ID(PD, 12), + MX27_PAD_ATA_DATA11 = PAD_ID(PD, 13), + MX27_PAD_ATA_DATA12 = PAD_ID(PD, 14), + MX27_PAD_ATA_DATA13 = PAD_ID(PD, 15), + MX27_PAD_ATA_DATA14 = PAD_ID(PD, 16), + MX27_PAD_I2C_DATA = PAD_ID(PD, 17), + MX27_PAD_I2C_CLK = PAD_ID(PD, 18), + MX27_PAD_CSPI2_SS2 = PAD_ID(PD, 19), + MX27_PAD_CSPI2_SS1 = PAD_ID(PD, 20), + MX27_PAD_CSPI2_SS0 = PAD_ID(PD, 21), + MX27_PAD_CSPI2_SCLK = PAD_ID(PD, 22), + MX27_PAD_CSPI2_MISO = PAD_ID(PD, 23), + MX27_PAD_CSPI2_MOSI = PAD_ID(PD, 24), + MX27_PAD_CSPI1_RDY = PAD_ID(PD, 25), + MX27_PAD_CSPI1_SS2 = PAD_ID(PD, 26), + MX27_PAD_CSPI1_SS1 = PAD_ID(PD, 27), + MX27_PAD_CSPI1_SS0 = PAD_ID(PD, 28), + MX27_PAD_CSPI1_SCLK = PAD_ID(PD, 29), + MX27_PAD_CSPI1_MISO = PAD_ID(PD, 30), + MX27_PAD_CSPI1_MOSI = PAD_ID(PD, 31), + + MX27_PAD_USBOTG_NXT = PAD_ID(PE, 0), + MX27_PAD_USBOTG_STP = PAD_ID(PE, 1), + MX27_PAD_USBOTG_DIR = PAD_ID(PE, 2), + MX27_PAD_UART2_CTS = PAD_ID(PE, 3), + MX27_PAD_UART2_RTS = PAD_ID(PE, 4), + MX27_PAD_PWMO = PAD_ID(PE, 5), + MX27_PAD_UART2_TXD = PAD_ID(PE, 6), + MX27_PAD_UART2_RXD = PAD_ID(PE, 7), + MX27_PAD_UART3_TXD = PAD_ID(PE, 8), + MX27_PAD_UART3_RXD = PAD_ID(PE, 9), + MX27_PAD_UART3_CTS = PAD_ID(PE, 10), + MX27_PAD_UART3_RTS = PAD_ID(PE, 11), + MX27_PAD_UART1_TXD = PAD_ID(PE, 12), + MX27_PAD_UART1_RXD = PAD_ID(PE, 13), + MX27_PAD_UART1_CTS = PAD_ID(PE, 14), + MX27_PAD_UART1_RTS = PAD_ID(PE, 15), + MX27_PAD_RTCK = PAD_ID(PE, 16), + MX27_PAD_RESET_OUT_B = PAD_ID(PE, 17), + MX27_PAD_SD1_D0 = PAD_ID(PE, 18), + MX27_PAD_SD1_D1 = PAD_ID(PE, 19), + MX27_PAD_SD1_D2 = PAD_ID(PE, 20), + MX27_PAD_SD1_D3 = PAD_ID(PE, 21), + MX27_PAD_SD1_CMD = PAD_ID(PE, 22), + MX27_PAD_SD1_CLK = PAD_ID(PE, 23), + MX27_PAD_USBOTG_CLK = PAD_ID(PE, 24), + MX27_PAD_USBOTG_DATA7 = PAD_ID(PE, 25), + MX27_PAD_UNUSED9 = PAD_ID(PE, 26), + MX27_PAD_UNUSED10 = PAD_ID(PE, 27), + MX27_PAD_UNUSED11 = PAD_ID(PE, 28), + MX27_PAD_UNUSED12 = PAD_ID(PE, 29), + MX27_PAD_UNUSED13 = PAD_ID(PE, 30), + MX27_PAD_UNUSED14 = PAD_ID(PE, 31), + + MX27_PAD_NFRB = PAD_ID(PF, 0), + MX27_PAD_NFCLE = PAD_ID(PF, 1), + MX27_PAD_NFWP_B = PAD_ID(PF, 2), + MX27_PAD_NFCE_B = PAD_ID(PF, 3), + MX27_PAD_NFALE = PAD_ID(PF, 4), + MX27_PAD_NFRE_B = PAD_ID(PF, 5), + MX27_PAD_NFWE_B = PAD_ID(PF, 6), + MX27_PAD_PC_POE = PAD_ID(PF, 7), + MX27_PAD_PC_RW_B = PAD_ID(PF, 8), + MX27_PAD_IOIS16 = PAD_ID(PF, 9), + MX27_PAD_PC_RST = PAD_ID(PF, 10), + MX27_PAD_PC_BVD2 = PAD_ID(PF, 11), + MX27_PAD_PC_BVD1 = PAD_ID(PF, 12), + MX27_PAD_PC_VS2 = PAD_ID(PF, 13), + MX27_PAD_PC_VS1 = PAD_ID(PF, 14), + MX27_PAD_CLKO = PAD_ID(PF, 15), + MX27_PAD_PC_PWRON = PAD_ID(PF, 16), + MX27_PAD_PC_READY = PAD_ID(PF, 17), + MX27_PAD_PC_WAIT_B = PAD_ID(PF, 18), + MX27_PAD_PC_CD2_B = PAD_ID(PF, 19), + MX27_PAD_PC_CD1_B = PAD_ID(PF, 20), + MX27_PAD_CS4_B = PAD_ID(PF, 21), + MX27_PAD_CS5_B = PAD_ID(PF, 22), + MX27_PAD_ATA_DATA15 = PAD_ID(PF, 23), + MX27_PAD_UNUSED15 = PAD_ID(PF, 24), + MX27_PAD_UNUSED16 = PAD_ID(PF, 25), + MX27_PAD_UNUSED17 = PAD_ID(PF, 26), + MX27_PAD_UNUSED18 = PAD_ID(PF, 27), + MX27_PAD_UNUSED19 = PAD_ID(PF, 28), + MX27_PAD_UNUSED20 = PAD_ID(PF, 29), + MX27_PAD_UNUSED21 = PAD_ID(PF, 30), + MX27_PAD_UNUSED22 = PAD_ID(PF, 31), +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx27_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX27_PAD_USBH2_CLK), + IMX_PINCTRL_PIN(MX27_PAD_USBH2_DIR), + IMX_PINCTRL_PIN(MX27_PAD_USBH2_DATA7), + IMX_PINCTRL_PIN(MX27_PAD_USBH2_NXT), + IMX_PINCTRL_PIN(MX27_PAD_USBH2_STP), + IMX_PINCTRL_PIN(MX27_PAD_LSCLK), + IMX_PINCTRL_PIN(MX27_PAD_LD0), + IMX_PINCTRL_PIN(MX27_PAD_LD1), + IMX_PINCTRL_PIN(MX27_PAD_LD2), + IMX_PINCTRL_PIN(MX27_PAD_LD3), + IMX_PINCTRL_PIN(MX27_PAD_LD4), + IMX_PINCTRL_PIN(MX27_PAD_LD5), + IMX_PINCTRL_PIN(MX27_PAD_LD6), + IMX_PINCTRL_PIN(MX27_PAD_LD7), + IMX_PINCTRL_PIN(MX27_PAD_LD8), + IMX_PINCTRL_PIN(MX27_PAD_LD9), + IMX_PINCTRL_PIN(MX27_PAD_LD10), + IMX_PINCTRL_PIN(MX27_PAD_LD11), + IMX_PINCTRL_PIN(MX27_PAD_LD12), + IMX_PINCTRL_PIN(MX27_PAD_LD13), + IMX_PINCTRL_PIN(MX27_PAD_LD14), + IMX_PINCTRL_PIN(MX27_PAD_LD15), + IMX_PINCTRL_PIN(MX27_PAD_LD16), + IMX_PINCTRL_PIN(MX27_PAD_LD17), + IMX_PINCTRL_PIN(MX27_PAD_REV), + IMX_PINCTRL_PIN(MX27_PAD_CLS), + IMX_PINCTRL_PIN(MX27_PAD_PS), + IMX_PINCTRL_PIN(MX27_PAD_SPL_SPR), + IMX_PINCTRL_PIN(MX27_PAD_HSYNC), + IMX_PINCTRL_PIN(MX27_PAD_VSYNC), + IMX_PINCTRL_PIN(MX27_PAD_CONTRAST), + IMX_PINCTRL_PIN(MX27_PAD_OE_ACD), + + IMX_PINCTRL_PIN(MX27_PAD_UNUSED0), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED1), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED2), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED3), + IMX_PINCTRL_PIN(MX27_PAD_SD2_D0), + IMX_PINCTRL_PIN(MX27_PAD_SD2_D1), + IMX_PINCTRL_PIN(MX27_PAD_SD2_D2), + IMX_PINCTRL_PIN(MX27_PAD_SD2_D3), + IMX_PINCTRL_PIN(MX27_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX27_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D0), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D1), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D2), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D3), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D4), + IMX_PINCTRL_PIN(MX27_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX27_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D5), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D6), + IMX_PINCTRL_PIN(MX27_PAD_CSI_D7), + IMX_PINCTRL_PIN(MX27_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX27_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_SUSP), + IMX_PINCTRL_PIN(MX27_PAD_USB_PWR), + IMX_PINCTRL_PIN(MX27_PAD_USB_OC_B), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_RCV), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_FS), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_OE_B), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_TXDM), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_TXDP), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_RXDM), + IMX_PINCTRL_PIN(MX27_PAD_USBH1_RXDP), + + IMX_PINCTRL_PIN(MX27_PAD_UNUSED4), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED5), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED6), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED7), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED8), + IMX_PINCTRL_PIN(MX27_PAD_I2C2_SDA), + IMX_PINCTRL_PIN(MX27_PAD_I2C2_SCL), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA5), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA6), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA0), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA2), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA1), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA4), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA3), + IMX_PINCTRL_PIN(MX27_PAD_TOUT), + IMX_PINCTRL_PIN(MX27_PAD_TIN), + IMX_PINCTRL_PIN(MX27_PAD_SSI4_FS), + IMX_PINCTRL_PIN(MX27_PAD_SSI4_RXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI4_TXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI4_CLK), + IMX_PINCTRL_PIN(MX27_PAD_SSI1_FS), + IMX_PINCTRL_PIN(MX27_PAD_SSI1_RXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI1_TXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI1_CLK), + IMX_PINCTRL_PIN(MX27_PAD_SSI2_FS), + IMX_PINCTRL_PIN(MX27_PAD_SSI2_RXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI2_TXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI2_CLK), + IMX_PINCTRL_PIN(MX27_PAD_SSI3_FS), + IMX_PINCTRL_PIN(MX27_PAD_SSI3_RXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI3_TXDAT), + IMX_PINCTRL_PIN(MX27_PAD_SSI3_CLK), + + IMX_PINCTRL_PIN(MX27_PAD_SD3_CMD), + IMX_PINCTRL_PIN(MX27_PAD_SD3_CLK), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA0), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA1), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA2), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA3), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA4), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA5), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA6), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA7), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA8), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA9), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA10), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA11), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA12), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA13), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA14), + IMX_PINCTRL_PIN(MX27_PAD_I2C_DATA), + IMX_PINCTRL_PIN(MX27_PAD_I2C_CLK), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_SS2), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_SS1), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_SS0), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_SCLK), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_MISO), + IMX_PINCTRL_PIN(MX27_PAD_CSPI2_MOSI), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_RDY), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_SS2), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_SS1), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_SS0), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_SCLK), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_MISO), + IMX_PINCTRL_PIN(MX27_PAD_CSPI1_MOSI), + + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_NXT), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_STP), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DIR), + IMX_PINCTRL_PIN(MX27_PAD_UART2_CTS), + IMX_PINCTRL_PIN(MX27_PAD_UART2_RTS), + IMX_PINCTRL_PIN(MX27_PAD_PWMO), + IMX_PINCTRL_PIN(MX27_PAD_UART2_TXD), + IMX_PINCTRL_PIN(MX27_PAD_UART2_RXD), + IMX_PINCTRL_PIN(MX27_PAD_UART3_TXD), + IMX_PINCTRL_PIN(MX27_PAD_UART3_RXD), + IMX_PINCTRL_PIN(MX27_PAD_UART3_CTS), + IMX_PINCTRL_PIN(MX27_PAD_UART3_RTS), + IMX_PINCTRL_PIN(MX27_PAD_UART1_TXD), + IMX_PINCTRL_PIN(MX27_PAD_UART1_RXD), + IMX_PINCTRL_PIN(MX27_PAD_UART1_CTS), + IMX_PINCTRL_PIN(MX27_PAD_UART1_RTS), + IMX_PINCTRL_PIN(MX27_PAD_RTCK), + IMX_PINCTRL_PIN(MX27_PAD_RESET_OUT_B), + IMX_PINCTRL_PIN(MX27_PAD_SD1_D0), + IMX_PINCTRL_PIN(MX27_PAD_SD1_D1), + IMX_PINCTRL_PIN(MX27_PAD_SD1_D2), + IMX_PINCTRL_PIN(MX27_PAD_SD1_D3), + IMX_PINCTRL_PIN(MX27_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX27_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_CLK), + IMX_PINCTRL_PIN(MX27_PAD_USBOTG_DATA7), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED9), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED10), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED11), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED12), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED13), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED14), + + IMX_PINCTRL_PIN(MX27_PAD_NFRB), + IMX_PINCTRL_PIN(MX27_PAD_NFCLE), + IMX_PINCTRL_PIN(MX27_PAD_NFWP_B), + IMX_PINCTRL_PIN(MX27_PAD_NFCE_B), + IMX_PINCTRL_PIN(MX27_PAD_NFALE), + IMX_PINCTRL_PIN(MX27_PAD_NFRE_B), + IMX_PINCTRL_PIN(MX27_PAD_NFWE_B), + IMX_PINCTRL_PIN(MX27_PAD_PC_POE), + IMX_PINCTRL_PIN(MX27_PAD_PC_RW_B), + IMX_PINCTRL_PIN(MX27_PAD_IOIS16), + IMX_PINCTRL_PIN(MX27_PAD_PC_RST), + IMX_PINCTRL_PIN(MX27_PAD_PC_BVD2), + IMX_PINCTRL_PIN(MX27_PAD_PC_BVD1), + IMX_PINCTRL_PIN(MX27_PAD_PC_VS2), + IMX_PINCTRL_PIN(MX27_PAD_PC_VS1), + IMX_PINCTRL_PIN(MX27_PAD_CLKO), + IMX_PINCTRL_PIN(MX27_PAD_PC_PWRON), + IMX_PINCTRL_PIN(MX27_PAD_PC_READY), + IMX_PINCTRL_PIN(MX27_PAD_PC_WAIT_B), + IMX_PINCTRL_PIN(MX27_PAD_PC_CD2_B), + IMX_PINCTRL_PIN(MX27_PAD_PC_CD1_B), + IMX_PINCTRL_PIN(MX27_PAD_CS4_B), + IMX_PINCTRL_PIN(MX27_PAD_CS5_B), + IMX_PINCTRL_PIN(MX27_PAD_ATA_DATA15), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED15), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED16), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED17), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED18), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED19), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED20), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED21), + IMX_PINCTRL_PIN(MX27_PAD_UNUSED22), +}; + +static struct imx1_pinctrl_soc_info imx27_pinctrl_info = { + .pins = imx27_pinctrl_pads, + .npins = ARRAY_SIZE(imx27_pinctrl_pads), +}; + +static struct of_device_id imx27_pinctrl_of_match[] = { + { .compatible = "fsl,imx27-iomuxc", }, + { /* sentinel */ } +}; + +struct imx27_pinctrl_private { + int num_gpio_childs; + struct platform_device **gpio_dev; + struct mxc_gpio_platform_data *gpio_pdata; +}; + +static int imx27_pinctrl_probe(struct platform_device *pdev) +{ + return imx1_pinctrl_core_probe(pdev, &imx27_pinctrl_info); +} + +static struct platform_driver imx27_pinctrl_driver = { + .driver = { + .name = "imx27-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx27_pinctrl_of_match), + }, + .probe = imx27_pinctrl_probe, + .remove = imx1_pinctrl_core_remove, +}; + +static int __init imx27_pinctrl_init(void) +{ + return platform_driver_register(&imx27_pinctrl_driver); +} +arch_initcall(imx27_pinctrl_init); + +static void __exit imx27_pinctrl_exit(void) +{ + platform_driver_unregister(&imx27_pinctrl_driver); +} +module_exit(imx27_pinctrl_exit); +MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); +MODULE_DESCRIPTION("Freescale IMX27 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/pinctrl-imx35.c index c4549829fc4..278a04ae894 100644 --- a/drivers/pinctrl/pinctrl-imx35.c +++ b/drivers/pinctrl/pinctrl-imx35.c @@ -1019,7 +1019,7 @@ static struct platform_driver imx35_pinctrl_driver = { .driver = { .name = "imx35-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx35_pinctrl_of_match), + .of_match_table = imx35_pinctrl_of_match, }, .probe = imx35_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-imx50.c b/drivers/pinctrl/pinctrl-imx50.c new file mode 100644 index 00000000000..b06feed1b03 --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx50.c @@ -0,0 +1,426 @@ +/* + * imx50 pinctrl driver based on imx pinmux core + * + * Copyright (C) 2013 Greg Ungerer <gerg@uclinux.org> + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/pinctrl.h> + +#include "pinctrl-imx.h" + +enum imx50_pads { + MX50_PAD_RESERVE0 = 0, + MX50_PAD_RESERVE1 = 1, + MX50_PAD_RESERVE2 = 2, + MX50_PAD_RESERVE3 = 3, + MX50_PAD_RESERVE4 = 4, + MX50_PAD_RESERVE5 = 5, + MX50_PAD_RESERVE6 = 6, + MX50_PAD_RESERVE7 = 7, + MX50_PAD_KEY_COL0 = 8, + MX50_PAD_KEY_ROW0 = 9, + MX50_PAD_KEY_COL1 = 10, + MX50_PAD_KEY_ROW1 = 11, + MX50_PAD_KEY_COL2 = 12, + MX50_PAD_KEY_ROW2 = 13, + MX50_PAD_KEY_COL3 = 14, + MX50_PAD_KEY_ROW3 = 15, + MX50_PAD_I2C1_SCL = 16, + MX50_PAD_I2C1_SDA = 17, + MX50_PAD_I2C2_SCL = 18, + MX50_PAD_I2C2_SDA = 19, + MX50_PAD_I2C3_SCL = 20, + MX50_PAD_I2C3_SDA = 21, + MX50_PAD_PWM1 = 22, + MX50_PAD_PWM2 = 23, + MX50_PAD_0WIRE = 24, + MX50_PAD_EPITO = 25, + MX50_PAD_WDOG = 26, + MX50_PAD_SSI_TXFS = 27, + MX50_PAD_SSI_TXC = 28, + MX50_PAD_SSI_TXD = 29, + MX50_PAD_SSI_RXD = 30, + MX50_PAD_SSI_RXF = 31, + MX50_PAD_SSI_RXC = 32, + MX50_PAD_UART1_TXD = 33, + MX50_PAD_UART1_RXD = 34, + MX50_PAD_UART1_CTS = 35, + MX50_PAD_UART1_RTS = 36, + MX50_PAD_UART2_TXD = 37, + MX50_PAD_UART2_RXD = 38, + MX50_PAD_UART2_CTS = 39, + MX50_PAD_UART2_RTS = 40, + MX50_PAD_UART3_TXD = 41, + MX50_PAD_UART3_RXD = 42, + MX50_PAD_UART4_TXD = 43, + MX50_PAD_UART4_RXD = 44, + MX50_PAD_CSPI_CLK = 45, + MX50_PAD_CSPI_MOSI = 46, + MX50_PAD_CSPI_MISO = 47, + MX50_PAD_CSPI_SS0 = 48, + MX50_PAD_ECSPI1_CLK = 49, + MX50_PAD_ECSPI1_MOSI = 50, + MX50_PAD_ECSPI1_MISO = 51, + MX50_PAD_ECSPI1_SS0 = 52, + MX50_PAD_ECSPI2_CLK = 53, + MX50_PAD_ECSPI2_MOSI = 54, + MX50_PAD_ECSPI2_MISO = 55, + MX50_PAD_ECSPI2_SS0 = 56, + MX50_PAD_SD1_CLK = 57, + MX50_PAD_SD1_CMD = 58, + MX50_PAD_SD1_D0 = 59, + MX50_PAD_SD1_D1 = 60, + MX50_PAD_SD1_D2 = 61, + MX50_PAD_SD1_D3 = 62, + MX50_PAD_SD2_CLK = 63, + MX50_PAD_SD2_CMD = 64, + MX50_PAD_SD2_D0 = 65, + MX50_PAD_SD2_D1 = 66, + MX50_PAD_SD2_D2 = 67, + MX50_PAD_SD2_D3 = 68, + MX50_PAD_SD2_D4 = 69, + MX50_PAD_SD2_D5 = 70, + MX50_PAD_SD2_D6 = 71, + MX50_PAD_SD2_D7 = 72, + MX50_PAD_SD2_WP = 73, + MX50_PAD_SD2_CD = 74, + MX50_PAD_DISP_D0 = 75, + MX50_PAD_DISP_D1 = 76, + MX50_PAD_DISP_D2 = 77, + MX50_PAD_DISP_D3 = 78, + MX50_PAD_DISP_D4 = 79, + MX50_PAD_DISP_D5 = 80, + MX50_PAD_DISP_D6 = 81, + MX50_PAD_DISP_D7 = 82, + MX50_PAD_DISP_WR = 83, + MX50_PAD_DISP_RD = 84, + MX50_PAD_DISP_RS = 85, + MX50_PAD_DISP_CS = 86, + MX50_PAD_DISP_BUSY = 87, + MX50_PAD_DISP_RESET = 88, + MX50_PAD_SD3_CLK = 89, + MX50_PAD_SD3_CMD = 90, + MX50_PAD_SD3_D0 = 91, + MX50_PAD_SD3_D1 = 92, + MX50_PAD_SD3_D2 = 93, + MX50_PAD_SD3_D3 = 94, + MX50_PAD_SD3_D4 = 95, + MX50_PAD_SD3_D5 = 96, + MX50_PAD_SD3_D6 = 97, + MX50_PAD_SD3_D7 = 98, + MX50_PAD_SD3_WP = 99, + MX50_PAD_DISP_D8 = 100, + MX50_PAD_DISP_D9 = 101, + MX50_PAD_DISP_D10 = 102, + MX50_PAD_DISP_D11 = 103, + MX50_PAD_DISP_D12 = 104, + MX50_PAD_DISP_D13 = 105, + MX50_PAD_DISP_D14 = 106, + MX50_PAD_DISP_D15 = 107, + MX50_PAD_EPDC_D0 = 108, + MX50_PAD_EPDC_D1 = 109, + MX50_PAD_EPDC_D2 = 110, + MX50_PAD_EPDC_D3 = 111, + MX50_PAD_EPDC_D4 = 112, + MX50_PAD_EPDC_D5 = 113, + MX50_PAD_EPDC_D6 = 114, + MX50_PAD_EPDC_D7 = 115, + MX50_PAD_EPDC_D8 = 116, + MX50_PAD_EPDC_D9 = 117, + MX50_PAD_EPDC_D10 = 118, + MX50_PAD_EPDC_D11 = 119, + MX50_PAD_EPDC_D12 = 120, + MX50_PAD_EPDC_D13 = 121, + MX50_PAD_EPDC_D14 = 122, + MX50_PAD_EPDC_D15 = 123, + MX50_PAD_EPDC_GDCLK = 124, + MX50_PAD_EPDC_GDSP = 125, + MX50_PAD_EPDC_GDOE = 126, + MX50_PAD_EPDC_GDRL = 127, + MX50_PAD_EPDC_SDCLK = 128, + MX50_PAD_EPDC_SDOEZ = 129, + MX50_PAD_EPDC_SDOED = 130, + MX50_PAD_EPDC_SDOE = 131, + MX50_PAD_EPDC_SDLE = 132, + MX50_PAD_EPDC_SDCLKN = 133, + MX50_PAD_EPDC_SDSHR = 134, + MX50_PAD_EPDC_PWRCOM = 135, + MX50_PAD_EPDC_PWRSTAT = 136, + MX50_PAD_EPDC_PWRCTRL0 = 137, + MX50_PAD_EPDC_PWRCTRL1 = 138, + MX50_PAD_EPDC_PWRCTRL2 = 139, + MX50_PAD_EPDC_PWRCTRL3 = 140, + MX50_PAD_EPDC_VCOM0 = 141, + MX50_PAD_EPDC_VCOM1 = 142, + MX50_PAD_EPDC_BDR0 = 143, + MX50_PAD_EPDC_BDR1 = 144, + MX50_PAD_EPDC_SDCE0 = 145, + MX50_PAD_EPDC_SDCE1 = 146, + MX50_PAD_EPDC_SDCE2 = 147, + MX50_PAD_EPDC_SDCE3 = 148, + MX50_PAD_EPDC_SDCE4 = 149, + MX50_PAD_EPDC_SDCE5 = 150, + MX50_PAD_EIM_DA0 = 151, + MX50_PAD_EIM_DA1 = 152, + MX50_PAD_EIM_DA2 = 153, + MX50_PAD_EIM_DA3 = 154, + MX50_PAD_EIM_DA4 = 155, + MX50_PAD_EIM_DA5 = 156, + MX50_PAD_EIM_DA6 = 157, + MX50_PAD_EIM_DA7 = 158, + MX50_PAD_EIM_DA8 = 159, + MX50_PAD_EIM_DA9 = 160, + MX50_PAD_EIM_DA10 = 161, + MX50_PAD_EIM_DA11 = 162, + MX50_PAD_EIM_DA12 = 163, + MX50_PAD_EIM_DA13 = 164, + MX50_PAD_EIM_DA14 = 165, + MX50_PAD_EIM_DA15 = 166, + MX50_PAD_EIM_CS2 = 167, + MX50_PAD_EIM_CS1 = 168, + MX50_PAD_EIM_CS0 = 169, + MX50_PAD_EIM_EB0 = 170, + MX50_PAD_EIM_EB1 = 171, + MX50_PAD_EIM_WAIT = 172, + MX50_PAD_EIM_BCLK = 173, + MX50_PAD_EIM_RDY = 174, + MX50_PAD_EIM_OE = 175, + MX50_PAD_EIM_RW = 176, + MX50_PAD_EIM_LBA = 177, + MX50_PAD_EIM_CRE = 178, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx50_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX50_PAD_RESERVE0), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE1), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE2), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE3), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE4), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE5), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE6), + IMX_PINCTRL_PIN(MX50_PAD_RESERVE7), + IMX_PINCTRL_PIN(MX50_PAD_KEY_COL0), + IMX_PINCTRL_PIN(MX50_PAD_KEY_ROW0), + IMX_PINCTRL_PIN(MX50_PAD_KEY_COL1), + IMX_PINCTRL_PIN(MX50_PAD_KEY_ROW1), + IMX_PINCTRL_PIN(MX50_PAD_KEY_COL2), + IMX_PINCTRL_PIN(MX50_PAD_KEY_ROW2), + IMX_PINCTRL_PIN(MX50_PAD_KEY_COL3), + IMX_PINCTRL_PIN(MX50_PAD_KEY_ROW3), + IMX_PINCTRL_PIN(MX50_PAD_I2C1_SCL), + IMX_PINCTRL_PIN(MX50_PAD_I2C1_SDA), + IMX_PINCTRL_PIN(MX50_PAD_I2C2_SCL), + IMX_PINCTRL_PIN(MX50_PAD_I2C2_SDA), + IMX_PINCTRL_PIN(MX50_PAD_I2C3_SCL), + IMX_PINCTRL_PIN(MX50_PAD_I2C3_SDA), + IMX_PINCTRL_PIN(MX50_PAD_PWM1), + IMX_PINCTRL_PIN(MX50_PAD_PWM2), + IMX_PINCTRL_PIN(MX50_PAD_0WIRE), + IMX_PINCTRL_PIN(MX50_PAD_EPITO), + IMX_PINCTRL_PIN(MX50_PAD_WDOG), + IMX_PINCTRL_PIN(MX50_PAD_SSI_TXFS), + IMX_PINCTRL_PIN(MX50_PAD_SSI_TXC), + IMX_PINCTRL_PIN(MX50_PAD_SSI_TXD), + IMX_PINCTRL_PIN(MX50_PAD_SSI_RXD), + IMX_PINCTRL_PIN(MX50_PAD_SSI_RXF), + IMX_PINCTRL_PIN(MX50_PAD_SSI_RXC), + IMX_PINCTRL_PIN(MX50_PAD_UART1_TXD), + IMX_PINCTRL_PIN(MX50_PAD_UART1_RXD), + IMX_PINCTRL_PIN(MX50_PAD_UART1_CTS), + IMX_PINCTRL_PIN(MX50_PAD_UART1_RTS), + IMX_PINCTRL_PIN(MX50_PAD_UART2_TXD), + IMX_PINCTRL_PIN(MX50_PAD_UART2_RXD), + IMX_PINCTRL_PIN(MX50_PAD_UART2_CTS), + IMX_PINCTRL_PIN(MX50_PAD_UART2_RTS), + IMX_PINCTRL_PIN(MX50_PAD_UART3_TXD), + IMX_PINCTRL_PIN(MX50_PAD_UART3_RXD), + IMX_PINCTRL_PIN(MX50_PAD_UART4_TXD), + IMX_PINCTRL_PIN(MX50_PAD_UART4_RXD), + IMX_PINCTRL_PIN(MX50_PAD_CSPI_CLK), + IMX_PINCTRL_PIN(MX50_PAD_CSPI_MOSI), + IMX_PINCTRL_PIN(MX50_PAD_CSPI_MISO), + IMX_PINCTRL_PIN(MX50_PAD_CSPI_SS0), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI1_CLK), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI1_MOSI), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI1_MISO), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI1_SS0), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI2_CLK), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI2_MOSI), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI2_MISO), + IMX_PINCTRL_PIN(MX50_PAD_ECSPI2_SS0), + IMX_PINCTRL_PIN(MX50_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX50_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX50_PAD_SD1_D0), + IMX_PINCTRL_PIN(MX50_PAD_SD1_D1), + IMX_PINCTRL_PIN(MX50_PAD_SD1_D2), + IMX_PINCTRL_PIN(MX50_PAD_SD1_D3), + IMX_PINCTRL_PIN(MX50_PAD_SD2_CLK), + IMX_PINCTRL_PIN(MX50_PAD_SD2_CMD), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D0), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D1), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D2), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D3), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D4), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D5), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D6), + IMX_PINCTRL_PIN(MX50_PAD_SD2_D7), + IMX_PINCTRL_PIN(MX50_PAD_SD2_WP), + IMX_PINCTRL_PIN(MX50_PAD_SD2_CD), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D0), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D1), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D2), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D3), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D4), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D5), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D6), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D7), + IMX_PINCTRL_PIN(MX50_PAD_DISP_WR), + IMX_PINCTRL_PIN(MX50_PAD_DISP_RD), + IMX_PINCTRL_PIN(MX50_PAD_DISP_RS), + IMX_PINCTRL_PIN(MX50_PAD_DISP_CS), + IMX_PINCTRL_PIN(MX50_PAD_DISP_BUSY), + IMX_PINCTRL_PIN(MX50_PAD_DISP_RESET), + IMX_PINCTRL_PIN(MX50_PAD_SD3_CLK), + IMX_PINCTRL_PIN(MX50_PAD_SD3_CMD), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D0), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D1), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D2), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D3), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D4), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D5), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D6), + IMX_PINCTRL_PIN(MX50_PAD_SD3_D7), + IMX_PINCTRL_PIN(MX50_PAD_SD3_WP), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D8), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D9), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D10), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D11), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D12), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D13), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D14), + IMX_PINCTRL_PIN(MX50_PAD_DISP_D15), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D0), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D1), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D2), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D3), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D4), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D5), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D6), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D7), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D8), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D9), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D10), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D11), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D12), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D13), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D14), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_D15), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_GDCLK), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_GDSP), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_GDOE), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_GDRL), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCLK), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDOEZ), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDOED), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDOE), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDLE), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCLKN), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDSHR), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRCOM), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRSTAT), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRCTRL0), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRCTRL1), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRCTRL2), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_PWRCTRL3), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_VCOM0), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_VCOM1), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_BDR0), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_BDR1), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE0), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE1), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE2), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE3), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE4), + IMX_PINCTRL_PIN(MX50_PAD_EPDC_SDCE5), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA0), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA1), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA2), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA3), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA4), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA5), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA6), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA7), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA8), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA9), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA10), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA11), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA12), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA13), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA14), + IMX_PINCTRL_PIN(MX50_PAD_EIM_DA15), + IMX_PINCTRL_PIN(MX50_PAD_EIM_CS2), + IMX_PINCTRL_PIN(MX50_PAD_EIM_CS1), + IMX_PINCTRL_PIN(MX50_PAD_EIM_CS0), + IMX_PINCTRL_PIN(MX50_PAD_EIM_EB0), + IMX_PINCTRL_PIN(MX50_PAD_EIM_EB1), + IMX_PINCTRL_PIN(MX50_PAD_EIM_WAIT), + IMX_PINCTRL_PIN(MX50_PAD_EIM_BCLK), + IMX_PINCTRL_PIN(MX50_PAD_EIM_RDY), + IMX_PINCTRL_PIN(MX50_PAD_EIM_OE), + IMX_PINCTRL_PIN(MX50_PAD_EIM_RW), + IMX_PINCTRL_PIN(MX50_PAD_EIM_LBA), + IMX_PINCTRL_PIN(MX50_PAD_EIM_CRE), +}; + +static struct imx_pinctrl_soc_info imx50_pinctrl_info = { + .pins = imx50_pinctrl_pads, + .npins = ARRAY_SIZE(imx50_pinctrl_pads), +}; + +static struct of_device_id imx50_pinctrl_of_match[] = { + { .compatible = "fsl,imx50-iomuxc", }, + { /* sentinel */ } +}; + +static int imx50_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx50_pinctrl_info); +} + +static struct platform_driver imx50_pinctrl_driver = { + .driver = { + .name = "imx50-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx50_pinctrl_of_match), + }, + .probe = imx50_pinctrl_probe, + .remove = imx_pinctrl_remove, +}; + +static int __init imx50_pinctrl_init(void) +{ + return platform_driver_register(&imx50_pinctrl_driver); +} +arch_initcall(imx50_pinctrl_init); + +static void __exit imx50_pinctrl_exit(void) +{ + platform_driver_unregister(&imx50_pinctrl_driver); +} +module_exit(imx50_pinctrl_exit); +MODULE_DESCRIPTION("Freescale IMX50 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-imx51.c b/drivers/pinctrl/pinctrl-imx51.c index db268b92007..19ab182bef6 100644 --- a/drivers/pinctrl/pinctrl-imx51.c +++ b/drivers/pinctrl/pinctrl-imx51.c @@ -782,7 +782,7 @@ static struct platform_driver imx51_pinctrl_driver = { .driver = { .name = "imx51-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx51_pinctrl_of_match), + .of_match_table = imx51_pinctrl_of_match, }, .probe = imx51_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/pinctrl-imx53.c index 17562ae9005..f8d45c4cfde 100644 --- a/drivers/pinctrl/pinctrl-imx53.c +++ b/drivers/pinctrl/pinctrl-imx53.c @@ -468,7 +468,7 @@ static struct platform_driver imx53_pinctrl_driver = { .driver = { .name = "imx53-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx53_pinctrl_of_match), + .of_match_table = imx53_pinctrl_of_match, }, .probe = imx53_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-imx6dl.c b/drivers/pinctrl/pinctrl-imx6dl.c index a76b7242793..db2a1489bd9 100644 --- a/drivers/pinctrl/pinctrl-imx6dl.c +++ b/drivers/pinctrl/pinctrl-imx6dl.c @@ -474,7 +474,7 @@ static struct platform_driver imx6dl_pinctrl_driver = { .driver = { .name = "imx6dl-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx6dl_pinctrl_of_match), + .of_match_table = imx6dl_pinctrl_of_match, }, .probe = imx6dl_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c index 76dd9c4949f..8eb5ac1bd5f 100644 --- a/drivers/pinctrl/pinctrl-imx6q.c +++ b/drivers/pinctrl/pinctrl-imx6q.c @@ -480,7 +480,7 @@ static struct platform_driver imx6q_pinctrl_driver = { .driver = { .name = "imx6q-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx6q_pinctrl_of_match), + .of_match_table = imx6q_pinctrl_of_match, }, .probe = imx6q_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-imx6sl.c b/drivers/pinctrl/pinctrl-imx6sl.c index 4eb7ccab5f2..f21b7389df3 100644 --- a/drivers/pinctrl/pinctrl-imx6sl.c +++ b/drivers/pinctrl/pinctrl-imx6sl.c @@ -380,7 +380,7 @@ static struct platform_driver imx6sl_pinctrl_driver = { .driver = { .name = "imx6sl-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(imx6sl_pinctrl_of_match), + .of_match_table = imx6sl_pinctrl_of_match, }, .probe = imx6sl_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index d7c3ae300fa..7111c3b5913 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -634,6 +634,10 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d) { struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) + dev_err(nmk_chip->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); clk_enable(nmk_chip->clk); nmk_gpio_irq_unmask(d); return 0; @@ -645,6 +649,7 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) nmk_gpio_irq_mask(d); clk_disable(nmk_chip->clk); + gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); } static struct irq_chip nmk_gpio_irq_chip = { diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c index 30c4d356cb3..f13d0e78a41 100644 --- a/drivers/pinctrl/pinctrl-palmas.c +++ b/drivers/pinctrl/pinctrl-palmas.c @@ -891,9 +891,6 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev, param = pinconf_to_config_param(configs[i]); param_val = pinconf_to_config_argument(configs[i]); - if (param == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) - continue; - switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_UP: @@ -962,26 +959,9 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev, return 0; } -static int palmas_pinconf_group_get(struct pinctrl_dev *pctldev, - unsigned group, unsigned long *config) -{ - dev_err(pctldev->dev, "palmas_pinconf_group_get op not supported\n"); - return -ENOTSUPP; -} - -static int palmas_pinconf_group_set(struct pinctrl_dev *pctldev, - unsigned group, unsigned long *configs, - unsigned num_configs) -{ - dev_err(pctldev->dev, "palmas_pinconf_group_set op not supported\n"); - return -ENOTSUPP; -} - static const struct pinconf_ops palmas_pinconf_ops = { .pin_config_get = palmas_pinconf_get, .pin_config_set = palmas_pinconf_set, - .pin_config_group_get = palmas_pinconf_group_get, - .pin_config_group_set = palmas_pinconf_group_set, }; static struct pinctrl_desc palmas_pinctrl_desc = { diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index e0718b7c4ab..e939c28cbf1 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -56,8 +56,20 @@ #define GPIO_EXT_PORT 0x50 #define GPIO_LS_SYNC 0x60 +enum rockchip_pinctrl_type { + RK2928, + RK3066B, + RK3188, +}; + +enum rockchip_pin_bank_type { + COMMON_BANK, + RK3188_BANK0, +}; + /** * @reg_base: register base of the gpio bank + * @reg_pull: optional separate register for additional pull settings * @clk: clock of the gpio bank * @irq: interrupt of the gpio bank * @pin_base: first pin number @@ -74,12 +86,14 @@ */ struct rockchip_pin_bank { void __iomem *reg_base; + void __iomem *reg_pull; struct clk *clk; int irq; u32 pin_base; u8 nr_pins; char *name; u8 bank_num; + enum rockchip_pin_bank_type bank_type; bool valid; struct device_node *of_node; struct rockchip_pinctrl *drvdata; @@ -87,7 +101,7 @@ struct rockchip_pin_bank { struct gpio_chip gpio_chip; struct pinctrl_gpio_range grange; spinlock_t slock; - + u32 toggle_edge_mode; }; #define PIN_BANK(id, pins, label) \ @@ -98,18 +112,16 @@ struct rockchip_pin_bank { } /** - * @pull_auto: some SoCs don't allow pulls to be specified as up or down, but - * instead decide this automatically based on the pad-type. */ struct rockchip_pin_ctrl { struct rockchip_pin_bank *pin_banks; u32 nr_banks; u32 nr_pins; char *label; + enum rockchip_pinctrl_type type; int mux_offset; - int pull_offset; - bool pull_auto; - int pull_bank_stride; + void (*pull_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, + void __iomem **reg, u8 *bit); }; struct rockchip_pin_config { @@ -148,6 +160,7 @@ struct rockchip_pmx_func { struct rockchip_pinctrl { void __iomem *reg_base; + void __iomem *reg_pull; struct device *dev; struct rockchip_pin_ctrl *ctrl; struct pinctrl_desc pctl; @@ -354,31 +367,92 @@ static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) spin_unlock_irqrestore(&bank->slock, flags); } +#define RK2928_PULL_OFFSET 0x118 +#define RK2928_PULL_PINS_PER_REG 16 +#define RK2928_PULL_BANK_STRIDE 8 + +static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, void __iomem **reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + *reg = info->reg_base + RK2928_PULL_OFFSET; + *reg += bank->bank_num * RK2928_PULL_BANK_STRIDE; + *reg += (pin_num / RK2928_PULL_PINS_PER_REG) * 4; + + *bit = pin_num % RK2928_PULL_PINS_PER_REG; +}; + +#define RK3188_PULL_BITS_PER_PIN 2 +#define RK3188_PULL_PINS_PER_REG 8 +#define RK3188_PULL_BANK_STRIDE 16 + +static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, void __iomem **reg, u8 *bit) +{ + struct rockchip_pinctrl *info = bank->drvdata; + + /* The first 12 pins of the first bank are located elsewhere */ + if (bank->bank_type == RK3188_BANK0 && pin_num < 12) { + *reg = bank->reg_pull + + ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); + *bit = pin_num % RK3188_PULL_PINS_PER_REG; + *bit *= RK3188_PULL_BITS_PER_PIN; + } else { + *reg = info->reg_pull - 4; + *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE; + *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); + + /* + * The bits in these registers have an inverse ordering + * with the lowest pin being in bits 15:14 and the highest + * pin in bits 1:0 + */ + *bit = 7 - (pin_num % RK3188_PULL_PINS_PER_REG); + *bit *= RK3188_PULL_BITS_PER_PIN; + } +} + static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) { struct rockchip_pinctrl *info = bank->drvdata; struct rockchip_pin_ctrl *ctrl = info->ctrl; void __iomem *reg; u8 bit; + u32 data; /* rk3066b does support any pulls */ - if (!ctrl->pull_offset) + if (ctrl->type == RK3066B) return PIN_CONFIG_BIAS_DISABLE; - reg = info->reg_base + ctrl->pull_offset; - - if (ctrl->pull_auto) { - reg += bank->bank_num * ctrl->pull_bank_stride; - reg += (pin_num / 16) * 4; - bit = pin_num % 16; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { + case RK2928: return !(readl_relaxed(reg) & BIT(bit)) ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT : PIN_CONFIG_BIAS_DISABLE; - } else { - dev_err(info->dev, "pull support for rk31xx not implemented\n"); + case RK3188: + data = readl_relaxed(reg) >> bit; + data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1; + + switch (data) { + case 0: + return PIN_CONFIG_BIAS_DISABLE; + case 1: + return PIN_CONFIG_BIAS_PULL_UP; + case 2: + return PIN_CONFIG_BIAS_PULL_DOWN; + case 3: + return PIN_CONFIG_BIAS_BUS_HOLD; + } + + dev_err(info->dev, "unknown pull setting\n"); return -EIO; - } + default: + dev_err(info->dev, "unsupported pinctrl type\n"); + return -EINVAL; + }; } static int rockchip_set_pull(struct rockchip_pin_bank *bank, @@ -395,22 +469,13 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, bank->bank_num, pin_num, pull); /* rk3066b does support any pulls */ - if (!ctrl->pull_offset) + if (ctrl->type == RK3066B) return pull ? -EINVAL : 0; - reg = info->reg_base + ctrl->pull_offset; - - if (ctrl->pull_auto) { - if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && - pull != PIN_CONFIG_BIAS_DISABLE) { - dev_err(info->dev, "only PIN_DEFAULT and DISABLE allowed\n"); - return -EINVAL; - } - - reg += bank->bank_num * ctrl->pull_bank_stride; - reg += (pin_num / 16) * 4; - bit = pin_num % 16; + ctrl->pull_calc_reg(bank, pin_num, ®, &bit); + switch (ctrl->type) { + case RK2928: spin_lock_irqsave(&bank->slock, flags); data = BIT(bit + 16); @@ -419,14 +484,38 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, writel(data, reg); spin_unlock_irqrestore(&bank->slock, flags); - } else { - if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) { - dev_err(info->dev, "pull direction (up/down) needs to be specified\n"); + break; + case RK3188: + spin_lock_irqsave(&bank->slock, flags); + + /* enable the write to the equivalent lower bits */ + data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16); + + switch (pull) { + case PIN_CONFIG_BIAS_DISABLE: + break; + case PIN_CONFIG_BIAS_PULL_UP: + data |= (1 << bit); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + data |= (2 << bit); + break; + case PIN_CONFIG_BIAS_BUS_HOLD: + data |= (3 << bit); + break; + default: + dev_err(info->dev, "unsupported pull setting %d\n", + pull); return -EINVAL; } - dev_err(info->dev, "pull support for rk31xx not implemented\n"); - return -EIO; + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + break; + default: + dev_err(info->dev, "unsupported pinctrl type\n"); + return -EINVAL; } return 0; @@ -556,20 +645,17 @@ static const struct pinmux_ops rockchip_pmx_ops = { static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, enum pin_config_param pull) { - /* rk3066b does support any pulls */ - if (!ctrl->pull_offset) + switch (ctrl->type) { + case RK2928: + return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT || + pull == PIN_CONFIG_BIAS_DISABLE); + case RK3066B: return pull ? false : true; - - if (ctrl->pull_auto) { - if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && - pull != PIN_CONFIG_BIAS_DISABLE) - return false; - } else { - if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT) - return false; + case RK3188: + return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT); } - return true; + return false; } /* set the pin config settings for a specified pin */ @@ -597,6 +683,7 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_BUS_HOLD: if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP; @@ -635,6 +722,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_BUS_HOLD: if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP; @@ -656,7 +744,11 @@ static const struct pinconf_ops rockchip_pinconf_ops = { .pin_config_set = rockchip_pinconf_set, }; -static const char *gpio_compat = "rockchip,gpio-bank"; +static const struct of_device_id rockchip_bank_match[] = { + { .compatible = "rockchip,gpio-bank" }, + { .compatible = "rockchip,rk3188-gpio-bank0" }, + {}, +}; static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info, struct device_node *np) @@ -664,7 +756,7 @@ static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info, struct device_node *child; for_each_child_of_node(np, child) { - if (of_device_is_compatible(child, gpio_compat)) + if (of_match_node(rockchip_bank_match, child)) continue; info->nfunctions++; @@ -807,8 +899,9 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev, i = 0; for_each_child_of_node(np, child) { - if (of_device_is_compatible(child, gpio_compat)) + if (of_match_node(rockchip_bank_match, child)) continue; + ret = rockchip_pinctrl_parse_functions(child, info, i++); if (ret) { dev_err(&pdev->dev, "failed to parse function\n"); @@ -985,7 +1078,9 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_get_chip(irq); struct rockchip_pin_bank *bank = irq_get_handler_data(irq); + u32 polarity = 0, data = 0; u32 pend; + bool edge_changed = false; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); @@ -993,6 +1088,12 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); + if (bank->toggle_edge_mode) { + polarity = readl_relaxed(bank->reg_base + + GPIO_INT_POLARITY); + data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT); + } + while (pend) { unsigned int virq; @@ -1007,9 +1108,30 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq); + /* + * Triggering IRQ on both rising and falling edge + * needs manual intervention. + */ + if (bank->toggle_edge_mode & BIT(irq)) { + if (data & BIT(irq)) + polarity &= ~BIT(irq); + else + polarity |= BIT(irq); + + edge_changed = true; + } + generic_handle_irq(virq); } + if (bank->toggle_edge_mode && edge_changed) { + /* Interrupt params should only be set with ints disabled */ + data = readl_relaxed(bank->reg_base + GPIO_INTEN); + writel_relaxed(0, bank->reg_base + GPIO_INTEN); + writel(polarity, bank->reg_base + GPIO_INT_POLARITY); + writel(data, bank->reg_base + GPIO_INTEN); + } + chained_irq_exit(chip, desc); } @@ -1022,6 +1144,12 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) u32 level; u32 data; + /* make sure the pin is configured as gpio input */ + rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + data &= ~mask; + writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); + if (type & IRQ_TYPE_EDGE_BOTH) __irq_set_handler_locked(d->irq, handle_edge_irq); else @@ -1033,19 +1161,37 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY); switch (type) { + case IRQ_TYPE_EDGE_BOTH: + bank->toggle_edge_mode |= mask; + level |= mask; + + /* + * Determine gpio state. If 1 next interrupt should be falling + * otherwise rising. + */ + data = readl(bank->reg_base + GPIO_EXT_PORT); + if (data & mask) + polarity &= ~mask; + else + polarity |= mask; + break; case IRQ_TYPE_EDGE_RISING: + bank->toggle_edge_mode &= ~mask; level |= mask; polarity |= mask; break; case IRQ_TYPE_EDGE_FALLING: + bank->toggle_edge_mode &= ~mask; level |= mask; polarity &= ~mask; break; case IRQ_TYPE_LEVEL_HIGH: + bank->toggle_edge_mode &= ~mask; level &= ~mask; polarity |= mask; break; case IRQ_TYPE_LEVEL_LOW: + bank->toggle_edge_mode &= ~mask; level &= ~mask; polarity &= ~mask; break; @@ -1059,12 +1205,6 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) irq_gc_unlock(gc); - /* make sure the pin is configured as gpio input */ - rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); - data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); - data &= ~mask; - writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); - return 0; } @@ -1205,6 +1345,26 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, if (IS_ERR(bank->reg_base)) return PTR_ERR(bank->reg_base); + /* + * special case, where parts of the pull setting-registers are + * part of the PMU register space + */ + if (of_device_is_compatible(bank->of_node, + "rockchip,rk3188-gpio-bank0")) { + bank->bank_type = RK3188_BANK0; + + if (of_address_to_resource(bank->of_node, 1, &res)) { + dev_err(dev, "cannot find IO resource for bank\n"); + return -ENOENT; + } + + bank->reg_pull = devm_ioremap_resource(dev, &res); + if (IS_ERR(bank->reg_pull)) + return PTR_ERR(bank->reg_pull); + } else { + bank->bank_type = COMMON_BANK; + } + bank->irq = irq_of_parse_and_map(bank->of_node, 0); bank->clk = of_clk_get(bank->of_node, 0); @@ -1289,6 +1449,14 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) if (IS_ERR(info->reg_base)) return PTR_ERR(info->reg_base); + /* The RK3188 has its pull registers in a separate place */ + if (ctrl->type == RK3188) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + info->reg_pull = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->reg_base)) + return PTR_ERR(info->reg_base); + } + ret = rockchip_gpiolib_register(pdev, info); if (ret) return ret; @@ -1315,10 +1483,9 @@ static struct rockchip_pin_ctrl rk2928_pin_ctrl = { .pin_banks = rk2928_pin_banks, .nr_banks = ARRAY_SIZE(rk2928_pin_banks), .label = "RK2928-GPIO", + .type = RK2928, .mux_offset = 0xa8, - .pull_offset = 0x118, - .pull_auto = 1, - .pull_bank_stride = 8, + .pull_calc_reg = rk2928_calc_pull_reg_and_bit, }; static struct rockchip_pin_bank rk3066a_pin_banks[] = { @@ -1334,10 +1501,9 @@ static struct rockchip_pin_ctrl rk3066a_pin_ctrl = { .pin_banks = rk3066a_pin_banks, .nr_banks = ARRAY_SIZE(rk3066a_pin_banks), .label = "RK3066a-GPIO", + .type = RK2928, .mux_offset = 0xa8, - .pull_offset = 0x118, - .pull_auto = 1, - .pull_bank_stride = 8, + .pull_calc_reg = rk2928_calc_pull_reg_and_bit, }; static struct rockchip_pin_bank rk3066b_pin_banks[] = { @@ -1351,8 +1517,8 @@ static struct rockchip_pin_ctrl rk3066b_pin_ctrl = { .pin_banks = rk3066b_pin_banks, .nr_banks = ARRAY_SIZE(rk3066b_pin_banks), .label = "RK3066b-GPIO", + .type = RK3066B, .mux_offset = 0x60, - .pull_offset = -EINVAL, }; static struct rockchip_pin_bank rk3188_pin_banks[] = { @@ -1366,9 +1532,9 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = { .pin_banks = rk3188_pin_banks, .nr_banks = ARRAY_SIZE(rk3188_pin_banks), .label = "RK3188-GPIO", + .type = RK3188, .mux_offset = 0x68, - .pull_offset = 0x164, - .pull_bank_stride = 16, + .pull_calc_reg = rk3188_calc_pull_reg_and_bit, }; static const struct of_device_id rockchip_pinctrl_dt_match[] = { diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 92a9d6c8db0..47ec2e8741e 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -1148,7 +1148,7 @@ static struct platform_driver samsung_pinctrl_driver = { .driver = { .name = "samsung-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), + .of_match_table = samsung_pinctrl_dt_match, }, }; diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 0846922b231..829b98c5c66 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1604,6 +1604,9 @@ static inline void pcs_irq_set(struct pcs_soc_data *pcs_soc, pcs->write(mask, pcswi->reg); raw_spin_unlock(&pcs->lock); } + + if (pcs_soc->rearm) + pcs_soc->rearm(); } /** @@ -1626,8 +1629,6 @@ static void pcs_irq_unmask(struct irq_data *d) struct pcs_soc_data *pcs_soc = irq_data_get_irq_chip_data(d); pcs_irq_set(pcs_soc, d->irq, true); - if (pcs_soc->rearm) - pcs_soc->rearm(); } /** @@ -1678,11 +1679,6 @@ static int pcs_irq_handle(struct pcs_soc_data *pcs_soc) } } - /* - * For debugging on omaps, you may want to call pcs_soc->rearm() - * here to see wake-up interrupts during runtime also. - */ - return count; } diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c new file mode 100644 index 00000000000..c5e0f6973a3 --- /dev/null +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -0,0 +1,875 @@ +/* + * Abilis Systems TB10x pin control driver + * + * Copyright (C) Abilis Systems 2012 + * + * Author: Christian Ruppert <christian.ruppert@abilis.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/stringify.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/machine.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/slab.h> + +#include "pinctrl-utils.h" + +#define TB10X_PORT1 (0) +#define TB10X_PORT2 (16) +#define TB10X_PORT3 (32) +#define TB10X_PORT4 (48) +#define TB10X_PORT5 (128) +#define TB10X_PORT6 (64) +#define TB10X_PORT7 (80) +#define TB10X_PORT8 (96) +#define TB10X_PORT9 (112) +#define TB10X_GPIOS (256) + +#define PCFG_PORT_BITWIDTH (2) +#define PCFG_PORT_MASK(PORT) \ + (((1 << PCFG_PORT_BITWIDTH) - 1) << (PCFG_PORT_BITWIDTH * (PORT))) + +static const struct pinctrl_pin_desc tb10x_pins[] = { + /* Port 1 */ + PINCTRL_PIN(TB10X_PORT1 + 0, "MICLK_S0"), + PINCTRL_PIN(TB10X_PORT1 + 1, "MISTRT_S0"), + PINCTRL_PIN(TB10X_PORT1 + 2, "MIVAL_S0"), + PINCTRL_PIN(TB10X_PORT1 + 3, "MDI_S0"), + PINCTRL_PIN(TB10X_PORT1 + 4, "GPIOA0"), + PINCTRL_PIN(TB10X_PORT1 + 5, "GPIOA1"), + PINCTRL_PIN(TB10X_PORT1 + 6, "GPIOA2"), + PINCTRL_PIN(TB10X_PORT1 + 7, "MDI_S1"), + PINCTRL_PIN(TB10X_PORT1 + 8, "MIVAL_S1"), + PINCTRL_PIN(TB10X_PORT1 + 9, "MISTRT_S1"), + PINCTRL_PIN(TB10X_PORT1 + 10, "MICLK_S1"), + /* Port 2 */ + PINCTRL_PIN(TB10X_PORT2 + 0, "MICLK_S2"), + PINCTRL_PIN(TB10X_PORT2 + 1, "MISTRT_S2"), + PINCTRL_PIN(TB10X_PORT2 + 2, "MIVAL_S2"), + PINCTRL_PIN(TB10X_PORT2 + 3, "MDI_S2"), + PINCTRL_PIN(TB10X_PORT2 + 4, "GPIOC0"), + PINCTRL_PIN(TB10X_PORT2 + 5, "GPIOC1"), + PINCTRL_PIN(TB10X_PORT2 + 6, "GPIOC2"), + PINCTRL_PIN(TB10X_PORT2 + 7, "MDI_S3"), + PINCTRL_PIN(TB10X_PORT2 + 8, "MIVAL_S3"), + PINCTRL_PIN(TB10X_PORT2 + 9, "MISTRT_S3"), + PINCTRL_PIN(TB10X_PORT2 + 10, "MICLK_S3"), + /* Port 3 */ + PINCTRL_PIN(TB10X_PORT3 + 0, "MICLK_S4"), + PINCTRL_PIN(TB10X_PORT3 + 1, "MISTRT_S4"), + PINCTRL_PIN(TB10X_PORT3 + 2, "MIVAL_S4"), + PINCTRL_PIN(TB10X_PORT3 + 3, "MDI_S4"), + PINCTRL_PIN(TB10X_PORT3 + 4, "GPIOE0"), + PINCTRL_PIN(TB10X_PORT3 + 5, "GPIOE1"), + PINCTRL_PIN(TB10X_PORT3 + 6, "GPIOE2"), + PINCTRL_PIN(TB10X_PORT3 + 7, "MDI_S5"), + PINCTRL_PIN(TB10X_PORT3 + 8, "MIVAL_S5"), + PINCTRL_PIN(TB10X_PORT3 + 9, "MISTRT_S5"), + PINCTRL_PIN(TB10X_PORT3 + 10, "MICLK_S5"), + /* Port 4 */ + PINCTRL_PIN(TB10X_PORT4 + 0, "MICLK_S6"), + PINCTRL_PIN(TB10X_PORT4 + 1, "MISTRT_S6"), + PINCTRL_PIN(TB10X_PORT4 + 2, "MIVAL_S6"), + PINCTRL_PIN(TB10X_PORT4 + 3, "MDI_S6"), + PINCTRL_PIN(TB10X_PORT4 + 4, "GPIOG0"), + PINCTRL_PIN(TB10X_PORT4 + 5, "GPIOG1"), + PINCTRL_PIN(TB10X_PORT4 + 6, "GPIOG2"), + PINCTRL_PIN(TB10X_PORT4 + 7, "MDI_S7"), + PINCTRL_PIN(TB10X_PORT4 + 8, "MIVAL_S7"), + PINCTRL_PIN(TB10X_PORT4 + 9, "MISTRT_S7"), + PINCTRL_PIN(TB10X_PORT4 + 10, "MICLK_S7"), + /* Port 5 */ + PINCTRL_PIN(TB10X_PORT5 + 0, "PC_CE1N"), + PINCTRL_PIN(TB10X_PORT5 + 1, "PC_CE2N"), + PINCTRL_PIN(TB10X_PORT5 + 2, "PC_REGN"), + PINCTRL_PIN(TB10X_PORT5 + 3, "PC_INPACKN"), + PINCTRL_PIN(TB10X_PORT5 + 4, "PC_OEN"), + PINCTRL_PIN(TB10X_PORT5 + 5, "PC_WEN"), + PINCTRL_PIN(TB10X_PORT5 + 6, "PC_IORDN"), + PINCTRL_PIN(TB10X_PORT5 + 7, "PC_IOWRN"), + PINCTRL_PIN(TB10X_PORT5 + 8, "PC_RDYIRQN"), + PINCTRL_PIN(TB10X_PORT5 + 9, "PC_WAITN"), + PINCTRL_PIN(TB10X_PORT5 + 10, "PC_A0"), + PINCTRL_PIN(TB10X_PORT5 + 11, "PC_A1"), + PINCTRL_PIN(TB10X_PORT5 + 12, "PC_A2"), + PINCTRL_PIN(TB10X_PORT5 + 13, "PC_A3"), + PINCTRL_PIN(TB10X_PORT5 + 14, "PC_A4"), + PINCTRL_PIN(TB10X_PORT5 + 15, "PC_A5"), + PINCTRL_PIN(TB10X_PORT5 + 16, "PC_A6"), + PINCTRL_PIN(TB10X_PORT5 + 17, "PC_A7"), + PINCTRL_PIN(TB10X_PORT5 + 18, "PC_A8"), + PINCTRL_PIN(TB10X_PORT5 + 19, "PC_A9"), + PINCTRL_PIN(TB10X_PORT5 + 20, "PC_A10"), + PINCTRL_PIN(TB10X_PORT5 + 21, "PC_A11"), + PINCTRL_PIN(TB10X_PORT5 + 22, "PC_A12"), + PINCTRL_PIN(TB10X_PORT5 + 23, "PC_A13"), + PINCTRL_PIN(TB10X_PORT5 + 24, "PC_A14"), + PINCTRL_PIN(TB10X_PORT5 + 25, "PC_D0"), + PINCTRL_PIN(TB10X_PORT5 + 26, "PC_D1"), + PINCTRL_PIN(TB10X_PORT5 + 27, "PC_D2"), + PINCTRL_PIN(TB10X_PORT5 + 28, "PC_D3"), + PINCTRL_PIN(TB10X_PORT5 + 29, "PC_D4"), + PINCTRL_PIN(TB10X_PORT5 + 30, "PC_D5"), + PINCTRL_PIN(TB10X_PORT5 + 31, "PC_D6"), + PINCTRL_PIN(TB10X_PORT5 + 32, "PC_D7"), + PINCTRL_PIN(TB10X_PORT5 + 33, "PC_MOSTRT"), + PINCTRL_PIN(TB10X_PORT5 + 34, "PC_MOVAL"), + PINCTRL_PIN(TB10X_PORT5 + 35, "PC_MDO0"), + PINCTRL_PIN(TB10X_PORT5 + 36, "PC_MDO1"), + PINCTRL_PIN(TB10X_PORT5 + 37, "PC_MDO2"), + PINCTRL_PIN(TB10X_PORT5 + 38, "PC_MDO3"), + PINCTRL_PIN(TB10X_PORT5 + 39, "PC_MDO4"), + PINCTRL_PIN(TB10X_PORT5 + 40, "PC_MDO5"), + PINCTRL_PIN(TB10X_PORT5 + 41, "PC_MDO6"), + PINCTRL_PIN(TB10X_PORT5 + 42, "PC_MDO7"), + PINCTRL_PIN(TB10X_PORT5 + 43, "PC_MISTRT"), + PINCTRL_PIN(TB10X_PORT5 + 44, "PC_MIVAL"), + PINCTRL_PIN(TB10X_PORT5 + 45, "PC_MDI0"), + PINCTRL_PIN(TB10X_PORT5 + 46, "PC_MDI1"), + PINCTRL_PIN(TB10X_PORT5 + 47, "PC_MDI2"), + PINCTRL_PIN(TB10X_PORT5 + 48, "PC_MDI3"), + PINCTRL_PIN(TB10X_PORT5 + 49, "PC_MDI4"), + PINCTRL_PIN(TB10X_PORT5 + 50, "PC_MDI5"), + PINCTRL_PIN(TB10X_PORT5 + 51, "PC_MDI6"), + PINCTRL_PIN(TB10X_PORT5 + 52, "PC_MDI7"), + PINCTRL_PIN(TB10X_PORT5 + 53, "PC_MICLK"), + /* Port 6 */ + PINCTRL_PIN(TB10X_PORT6 + 0, "T_MOSTRT_S0"), + PINCTRL_PIN(TB10X_PORT6 + 1, "T_MOVAL_S0"), + PINCTRL_PIN(TB10X_PORT6 + 2, "T_MDO_S0"), + PINCTRL_PIN(TB10X_PORT6 + 3, "T_MOSTRT_S1"), + PINCTRL_PIN(TB10X_PORT6 + 4, "T_MOVAL_S1"), + PINCTRL_PIN(TB10X_PORT6 + 5, "T_MDO_S1"), + PINCTRL_PIN(TB10X_PORT6 + 6, "T_MOSTRT_S2"), + PINCTRL_PIN(TB10X_PORT6 + 7, "T_MOVAL_S2"), + PINCTRL_PIN(TB10X_PORT6 + 8, "T_MDO_S2"), + PINCTRL_PIN(TB10X_PORT6 + 9, "T_MOSTRT_S3"), + /* Port 7 */ + PINCTRL_PIN(TB10X_PORT7 + 0, "UART0_TXD"), + PINCTRL_PIN(TB10X_PORT7 + 1, "UART0_RXD"), + PINCTRL_PIN(TB10X_PORT7 + 2, "UART0_CTS"), + PINCTRL_PIN(TB10X_PORT7 + 3, "UART0_RTS"), + PINCTRL_PIN(TB10X_PORT7 + 4, "UART1_TXD"), + PINCTRL_PIN(TB10X_PORT7 + 5, "UART1_RXD"), + PINCTRL_PIN(TB10X_PORT7 + 6, "UART1_CTS"), + PINCTRL_PIN(TB10X_PORT7 + 7, "UART1_RTS"), + /* Port 8 */ + PINCTRL_PIN(TB10X_PORT8 + 0, "SPI3_CLK"), + PINCTRL_PIN(TB10X_PORT8 + 1, "SPI3_MISO"), + PINCTRL_PIN(TB10X_PORT8 + 2, "SPI3_MOSI"), + PINCTRL_PIN(TB10X_PORT8 + 3, "SPI3_SSN"), + /* Port 9 */ + PINCTRL_PIN(TB10X_PORT9 + 0, "SPI1_CLK"), + PINCTRL_PIN(TB10X_PORT9 + 1, "SPI1_MISO"), + PINCTRL_PIN(TB10X_PORT9 + 2, "SPI1_MOSI"), + PINCTRL_PIN(TB10X_PORT9 + 3, "SPI1_SSN0"), + PINCTRL_PIN(TB10X_PORT9 + 4, "SPI1_SSN1"), + /* Unmuxed GPIOs */ + PINCTRL_PIN(TB10X_GPIOS + 0, "GPIOB0"), + PINCTRL_PIN(TB10X_GPIOS + 1, "GPIOB1"), + + PINCTRL_PIN(TB10X_GPIOS + 2, "GPIOD0"), + PINCTRL_PIN(TB10X_GPIOS + 3, "GPIOD1"), + + PINCTRL_PIN(TB10X_GPIOS + 4, "GPIOF0"), + PINCTRL_PIN(TB10X_GPIOS + 5, "GPIOF1"), + + PINCTRL_PIN(TB10X_GPIOS + 6, "GPIOH0"), + PINCTRL_PIN(TB10X_GPIOS + 7, "GPIOH1"), + + PINCTRL_PIN(TB10X_GPIOS + 8, "GPIOI0"), + PINCTRL_PIN(TB10X_GPIOS + 9, "GPIOI1"), + PINCTRL_PIN(TB10X_GPIOS + 10, "GPIOI2"), + PINCTRL_PIN(TB10X_GPIOS + 11, "GPIOI3"), + PINCTRL_PIN(TB10X_GPIOS + 12, "GPIOI4"), + PINCTRL_PIN(TB10X_GPIOS + 13, "GPIOI5"), + PINCTRL_PIN(TB10X_GPIOS + 14, "GPIOI6"), + PINCTRL_PIN(TB10X_GPIOS + 15, "GPIOI7"), + PINCTRL_PIN(TB10X_GPIOS + 16, "GPIOI8"), + PINCTRL_PIN(TB10X_GPIOS + 17, "GPIOI9"), + PINCTRL_PIN(TB10X_GPIOS + 18, "GPIOI10"), + PINCTRL_PIN(TB10X_GPIOS + 19, "GPIOI11"), + + PINCTRL_PIN(TB10X_GPIOS + 20, "GPION0"), + PINCTRL_PIN(TB10X_GPIOS + 21, "GPION1"), + PINCTRL_PIN(TB10X_GPIOS + 22, "GPION2"), + PINCTRL_PIN(TB10X_GPIOS + 23, "GPION3"), +#define MAX_PIN (TB10X_GPIOS + 24) + PINCTRL_PIN(MAX_PIN, "GPION4"), +}; + + +/* Port 1 */ +static const unsigned mis0_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, + TB10X_PORT1 + 2, TB10X_PORT1 + 3}; +static const unsigned gpioa_pins[] = { TB10X_PORT1 + 4, TB10X_PORT1 + 5, + TB10X_PORT1 + 6}; +static const unsigned mis1_pins[] = { TB10X_PORT1 + 7, TB10X_PORT1 + 8, + TB10X_PORT1 + 9, TB10X_PORT1 + 10}; +static const unsigned mip1_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, + TB10X_PORT1 + 2, TB10X_PORT1 + 3, + TB10X_PORT1 + 4, TB10X_PORT1 + 5, + TB10X_PORT1 + 6, TB10X_PORT1 + 7, + TB10X_PORT1 + 8, TB10X_PORT1 + 9, + TB10X_PORT1 + 10}; + +/* Port 2 */ +static const unsigned mis2_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, + TB10X_PORT2 + 2, TB10X_PORT2 + 3}; +static const unsigned gpioc_pins[] = { TB10X_PORT2 + 4, TB10X_PORT2 + 5, + TB10X_PORT2 + 6}; +static const unsigned mis3_pins[] = { TB10X_PORT2 + 7, TB10X_PORT2 + 8, + TB10X_PORT2 + 9, TB10X_PORT2 + 10}; +static const unsigned mip3_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, + TB10X_PORT2 + 2, TB10X_PORT2 + 3, + TB10X_PORT2 + 4, TB10X_PORT2 + 5, + TB10X_PORT2 + 6, TB10X_PORT2 + 7, + TB10X_PORT2 + 8, TB10X_PORT2 + 9, + TB10X_PORT2 + 10}; + +/* Port 3 */ +static const unsigned mis4_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, + TB10X_PORT3 + 2, TB10X_PORT3 + 3}; +static const unsigned gpioe_pins[] = { TB10X_PORT3 + 4, TB10X_PORT3 + 5, + TB10X_PORT3 + 6}; +static const unsigned mis5_pins[] = { TB10X_PORT3 + 7, TB10X_PORT3 + 8, + TB10X_PORT3 + 9, TB10X_PORT3 + 10}; +static const unsigned mip5_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, + TB10X_PORT3 + 2, TB10X_PORT3 + 3, + TB10X_PORT3 + 4, TB10X_PORT3 + 5, + TB10X_PORT3 + 6, TB10X_PORT3 + 7, + TB10X_PORT3 + 8, TB10X_PORT3 + 9, + TB10X_PORT3 + 10}; + +/* Port 4 */ +static const unsigned mis6_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, + TB10X_PORT4 + 2, TB10X_PORT4 + 3}; +static const unsigned gpiog_pins[] = { TB10X_PORT4 + 4, TB10X_PORT4 + 5, + TB10X_PORT4 + 6}; +static const unsigned mis7_pins[] = { TB10X_PORT4 + 7, TB10X_PORT4 + 8, + TB10X_PORT4 + 9, TB10X_PORT4 + 10}; +static const unsigned mip7_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, + TB10X_PORT4 + 2, TB10X_PORT4 + 3, + TB10X_PORT4 + 4, TB10X_PORT4 + 5, + TB10X_PORT4 + 6, TB10X_PORT4 + 7, + TB10X_PORT4 + 8, TB10X_PORT4 + 9, + TB10X_PORT4 + 10}; + +/* Port 6 */ +static const unsigned mop_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, + TB10X_PORT6 + 2, TB10X_PORT6 + 3, + TB10X_PORT6 + 4, TB10X_PORT6 + 5, + TB10X_PORT6 + 6, TB10X_PORT6 + 7, + TB10X_PORT6 + 8, TB10X_PORT6 + 9}; +static const unsigned mos0_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, + TB10X_PORT6 + 2}; +static const unsigned mos1_pins[] = { TB10X_PORT6 + 3, TB10X_PORT6 + 4, + TB10X_PORT6 + 5}; +static const unsigned mos2_pins[] = { TB10X_PORT6 + 6, TB10X_PORT6 + 7, + TB10X_PORT6 + 8}; +static const unsigned mos3_pins[] = { TB10X_PORT6 + 9}; + +/* Port 7 */ +static const unsigned uart0_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, + TB10X_PORT7 + 2, TB10X_PORT7 + 3}; +static const unsigned uart1_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, + TB10X_PORT7 + 6, TB10X_PORT7 + 7}; +static const unsigned gpiol_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, + TB10X_PORT7 + 2, TB10X_PORT7 + 3}; +static const unsigned gpiom_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, + TB10X_PORT7 + 6, TB10X_PORT7 + 7}; + +/* Port 8 */ +static const unsigned spi3_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, + TB10X_PORT8 + 2, TB10X_PORT8 + 3}; +static const unsigned jtag_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, + TB10X_PORT8 + 2, TB10X_PORT8 + 3}; + +/* Port 9 */ +static const unsigned spi1_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, + TB10X_PORT9 + 2, TB10X_PORT9 + 3, + TB10X_PORT9 + 4}; +static const unsigned gpion_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, + TB10X_PORT9 + 2, TB10X_PORT9 + 3, + TB10X_PORT9 + 4}; + +/* Port 5 */ +static const unsigned gpioj_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, + TB10X_PORT5 + 2, TB10X_PORT5 + 3, + TB10X_PORT5 + 4, TB10X_PORT5 + 5, + TB10X_PORT5 + 6, TB10X_PORT5 + 7, + TB10X_PORT5 + 8, TB10X_PORT5 + 9, + TB10X_PORT5 + 10, TB10X_PORT5 + 11, + TB10X_PORT5 + 12, TB10X_PORT5 + 13, + TB10X_PORT5 + 14, TB10X_PORT5 + 15, + TB10X_PORT5 + 16, TB10X_PORT5 + 17, + TB10X_PORT5 + 18, TB10X_PORT5 + 19, + TB10X_PORT5 + 20, TB10X_PORT5 + 21, + TB10X_PORT5 + 22, TB10X_PORT5 + 23, + TB10X_PORT5 + 24, TB10X_PORT5 + 25, + TB10X_PORT5 + 26, TB10X_PORT5 + 27, + TB10X_PORT5 + 28, TB10X_PORT5 + 29, + TB10X_PORT5 + 30, TB10X_PORT5 + 31}; +static const unsigned gpiok_pins[] = { TB10X_PORT5 + 32, TB10X_PORT5 + 33, + TB10X_PORT5 + 34, TB10X_PORT5 + 35, + TB10X_PORT5 + 36, TB10X_PORT5 + 37, + TB10X_PORT5 + 38, TB10X_PORT5 + 39, + TB10X_PORT5 + 40, TB10X_PORT5 + 41, + TB10X_PORT5 + 42, TB10X_PORT5 + 43, + TB10X_PORT5 + 44, TB10X_PORT5 + 45, + TB10X_PORT5 + 46, TB10X_PORT5 + 47, + TB10X_PORT5 + 48, TB10X_PORT5 + 49, + TB10X_PORT5 + 50, TB10X_PORT5 + 51, + TB10X_PORT5 + 52, TB10X_PORT5 + 53}; +static const unsigned ciplus_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, + TB10X_PORT5 + 2, TB10X_PORT5 + 3, + TB10X_PORT5 + 4, TB10X_PORT5 + 5, + TB10X_PORT5 + 6, TB10X_PORT5 + 7, + TB10X_PORT5 + 8, TB10X_PORT5 + 9, + TB10X_PORT5 + 10, TB10X_PORT5 + 11, + TB10X_PORT5 + 12, TB10X_PORT5 + 13, + TB10X_PORT5 + 14, TB10X_PORT5 + 15, + TB10X_PORT5 + 16, TB10X_PORT5 + 17, + TB10X_PORT5 + 18, TB10X_PORT5 + 19, + TB10X_PORT5 + 20, TB10X_PORT5 + 21, + TB10X_PORT5 + 22, TB10X_PORT5 + 23, + TB10X_PORT5 + 24, TB10X_PORT5 + 25, + TB10X_PORT5 + 26, TB10X_PORT5 + 27, + TB10X_PORT5 + 28, TB10X_PORT5 + 29, + TB10X_PORT5 + 30, TB10X_PORT5 + 31, + TB10X_PORT5 + 32, TB10X_PORT5 + 33, + TB10X_PORT5 + 34, TB10X_PORT5 + 35, + TB10X_PORT5 + 36, TB10X_PORT5 + 37, + TB10X_PORT5 + 38, TB10X_PORT5 + 39, + TB10X_PORT5 + 40, TB10X_PORT5 + 41, + TB10X_PORT5 + 42, TB10X_PORT5 + 43, + TB10X_PORT5 + 44, TB10X_PORT5 + 45, + TB10X_PORT5 + 46, TB10X_PORT5 + 47, + TB10X_PORT5 + 48, TB10X_PORT5 + 49, + TB10X_PORT5 + 50, TB10X_PORT5 + 51, + TB10X_PORT5 + 52, TB10X_PORT5 + 53}; +static const unsigned mcard_pins[] = { TB10X_PORT5 + 3, TB10X_PORT5 + 10, + TB10X_PORT5 + 11, TB10X_PORT5 + 12, + TB10X_PORT5 + 22, TB10X_PORT5 + 23, + TB10X_PORT5 + 33, TB10X_PORT5 + 35, + TB10X_PORT5 + 36, TB10X_PORT5 + 37, + TB10X_PORT5 + 38, TB10X_PORT5 + 39, + TB10X_PORT5 + 40, TB10X_PORT5 + 41, + TB10X_PORT5 + 42, TB10X_PORT5 + 43, + TB10X_PORT5 + 45, TB10X_PORT5 + 46, + TB10X_PORT5 + 47, TB10X_PORT5 + 48, + TB10X_PORT5 + 49, TB10X_PORT5 + 50, + TB10X_PORT5 + 51, TB10X_PORT5 + 52, + TB10X_PORT5 + 53}; +static const unsigned stc0_pins[] = { TB10X_PORT5 + 34, TB10X_PORT5 + 35, + TB10X_PORT5 + 36, TB10X_PORT5 + 37, + TB10X_PORT5 + 38, TB10X_PORT5 + 39, + TB10X_PORT5 + 40}; +static const unsigned stc1_pins[] = { TB10X_PORT5 + 25, TB10X_PORT5 + 26, + TB10X_PORT5 + 27, TB10X_PORT5 + 28, + TB10X_PORT5 + 29, TB10X_PORT5 + 30, + TB10X_PORT5 + 44}; + +/* Unmuxed GPIOs */ +static const unsigned gpiob_pins[] = { TB10X_GPIOS + 0, TB10X_GPIOS + 1}; +static const unsigned gpiod_pins[] = { TB10X_GPIOS + 2, TB10X_GPIOS + 3}; +static const unsigned gpiof_pins[] = { TB10X_GPIOS + 4, TB10X_GPIOS + 5}; +static const unsigned gpioh_pins[] = { TB10X_GPIOS + 6, TB10X_GPIOS + 7}; +static const unsigned gpioi_pins[] = { TB10X_GPIOS + 8, TB10X_GPIOS + 9, + TB10X_GPIOS + 10, TB10X_GPIOS + 11, + TB10X_GPIOS + 12, TB10X_GPIOS + 13, + TB10X_GPIOS + 14, TB10X_GPIOS + 15, + TB10X_GPIOS + 16, TB10X_GPIOS + 17, + TB10X_GPIOS + 18, TB10X_GPIOS + 19}; + +struct tb10x_pinfuncgrp { + const char *name; + const unsigned int *pins; + const unsigned int pincnt; + const int port; + const unsigned int mode; + const int isgpio; +}; +#define DEFPINFUNCGRP(NAME, PORT, MODE, ISGPIO) { \ + .name = __stringify(NAME), \ + .pins = NAME##_pins, .pincnt = ARRAY_SIZE(NAME##_pins), \ + .port = (PORT), .mode = (MODE), \ + .isgpio = (ISGPIO), \ + } +static const struct tb10x_pinfuncgrp tb10x_pingroups[] = { + DEFPINFUNCGRP(mis0, 0, 0, 0), + DEFPINFUNCGRP(gpioa, 0, 0, 1), + DEFPINFUNCGRP(mis1, 0, 0, 0), + DEFPINFUNCGRP(mip1, 0, 1, 0), + DEFPINFUNCGRP(mis2, 1, 0, 0), + DEFPINFUNCGRP(gpioc, 1, 0, 1), + DEFPINFUNCGRP(mis3, 1, 0, 0), + DEFPINFUNCGRP(mip3, 1, 1, 0), + DEFPINFUNCGRP(mis4, 2, 0, 0), + DEFPINFUNCGRP(gpioe, 2, 0, 1), + DEFPINFUNCGRP(mis5, 2, 0, 0), + DEFPINFUNCGRP(mip5, 2, 1, 0), + DEFPINFUNCGRP(mis6, 3, 0, 0), + DEFPINFUNCGRP(gpiog, 3, 0, 1), + DEFPINFUNCGRP(mis7, 3, 0, 0), + DEFPINFUNCGRP(mip7, 3, 1, 0), + DEFPINFUNCGRP(gpioj, 4, 0, 1), + DEFPINFUNCGRP(gpiok, 4, 0, 1), + DEFPINFUNCGRP(ciplus, 4, 1, 0), + DEFPINFUNCGRP(mcard, 4, 2, 0), + DEFPINFUNCGRP(stc0, 4, 3, 0), + DEFPINFUNCGRP(stc1, 4, 3, 0), + DEFPINFUNCGRP(mop, 5, 0, 0), + DEFPINFUNCGRP(mos0, 5, 1, 0), + DEFPINFUNCGRP(mos1, 5, 1, 0), + DEFPINFUNCGRP(mos2, 5, 1, 0), + DEFPINFUNCGRP(mos3, 5, 1, 0), + DEFPINFUNCGRP(uart0, 6, 0, 0), + DEFPINFUNCGRP(uart1, 6, 0, 0), + DEFPINFUNCGRP(gpiol, 6, 1, 1), + DEFPINFUNCGRP(gpiom, 6, 1, 1), + DEFPINFUNCGRP(spi3, 7, 0, 0), + DEFPINFUNCGRP(jtag, 7, 1, 0), + DEFPINFUNCGRP(spi1, 8, 0, 0), + DEFPINFUNCGRP(gpion, 8, 1, 1), + DEFPINFUNCGRP(gpiob, -1, 0, 1), + DEFPINFUNCGRP(gpiod, -1, 0, 1), + DEFPINFUNCGRP(gpiof, -1, 0, 1), + DEFPINFUNCGRP(gpioh, -1, 0, 1), + DEFPINFUNCGRP(gpioi, -1, 0, 1), +}; +#undef DEFPINFUNCGRP + +struct tb10x_of_pinfunc { + const char *name; + const char *group; +}; + +#define TB10X_PORTS (9) + +/** + * struct tb10x_port - state of an I/O port + * @mode: Node this port is currently in. + * @count: Number of enabled functions which require this port to be + * configured in @mode. + */ +struct tb10x_port { + unsigned int mode; + unsigned int count; +}; + +/** + * struct tb10x_pinctrl - TB10x pin controller internal state + * @pctl: pointer to the pinctrl_dev structure of this pin controller. + * @base: register set base address. + * @pingroups: pointer to an array of the pin groups this driver manages. + * @pinfuncgrpcnt: number of pingroups in @pingroups. + * @pinfuncs: pointer to an array of pin functions this driver manages. + * @pinfuncnt: number of pin functions in @pinfuncs. + * @mutex: mutex for exclusive access to a pin controller's state. + * @ports: current state of each port. + * @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0). + */ +struct tb10x_pinctrl { + struct pinctrl_dev *pctl; + void *base; + const struct tb10x_pinfuncgrp *pingroups; + unsigned int pinfuncgrpcnt; + struct tb10x_of_pinfunc *pinfuncs; + unsigned int pinfuncnt; + struct mutex mutex; + struct tb10x_port ports[TB10X_PORTS]; + DECLARE_BITMAP(gpios, MAX_PIN + 1); +}; + +static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state, + unsigned int port, unsigned int mode) +{ + u32 pcfg; + + if (state->ports[port].count) + return; + + state->ports[port].mode = mode; + + pcfg = ioread32(state->base) & ~(PCFG_PORT_MASK(port)); + pcfg |= (mode << (PCFG_PORT_BITWIDTH * port)) & PCFG_PORT_MASK(port); + iowrite32(pcfg, state->base); +} + +static inline unsigned int tb10x_pinctrl_get_config( + struct tb10x_pinctrl *state, + unsigned int port) +{ + return (ioread32(state->base) & PCFG_PORT_MASK(port)) + >> (PCFG_PORT_BITWIDTH * port); +} + +static int tb10x_get_groups_count(struct pinctrl_dev *pctl) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + return state->pinfuncgrpcnt; +} + +static const char *tb10x_get_group_name(struct pinctrl_dev *pctl, unsigned n) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + return state->pingroups[n].name; +} + +static int tb10x_get_group_pins(struct pinctrl_dev *pctl, unsigned n, + unsigned const **pins, + unsigned * const num_pins) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + + *pins = state->pingroups[n].pins; + *num_pins = state->pingroups[n].pincnt; + + return 0; +} + +static int tb10x_dt_node_to_map(struct pinctrl_dev *pctl, + struct device_node *np_config, + struct pinctrl_map **map, unsigned *num_maps) +{ + const char *string; + unsigned reserved_maps = 0; + int ret = 0; + + if (of_property_read_string(np_config, "abilis,function", &string)) { + pr_err("%s: No abilis,function property in device tree.\n", + np_config->full_name); + return -EINVAL; + } + + *map = NULL; + *num_maps = 0; + + ret = pinctrl_utils_reserve_map(pctl, map, &reserved_maps, + num_maps, 1); + if (ret) + goto out; + + ret = pinctrl_utils_add_map_mux(pctl, map, &reserved_maps, + num_maps, string, np_config->name); + +out: + return ret; +} + +static struct pinctrl_ops tb10x_pinctrl_ops = { + .get_groups_count = tb10x_get_groups_count, + .get_group_name = tb10x_get_group_name, + .get_group_pins = tb10x_get_group_pins, + .dt_node_to_map = tb10x_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int tb10x_get_functions_count(struct pinctrl_dev *pctl) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + return state->pinfuncnt; +} + +static const char *tb10x_get_function_name(struct pinctrl_dev *pctl, + unsigned n) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + return state->pinfuncs[n].name; +} + +static int tb10x_get_function_groups(struct pinctrl_dev *pctl, + unsigned n, const char * const **groups, + unsigned * const num_groups) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + + *groups = &state->pinfuncs[n].group; + *num_groups = 1; + + return 0; +} + +static int tb10x_gpio_request_enable(struct pinctrl_dev *pctl, + struct pinctrl_gpio_range *range, + unsigned pin) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + int muxport = -1; + int muxmode = -1; + int i; + + mutex_lock(&state->mutex); + + /* + * Figure out to which port the requested GPIO belongs and how to + * configure that port. + * This loop also checks for pin conflicts between GPIOs and other + * functions. + */ + for (i = 0; i < state->pinfuncgrpcnt; i++) { + const struct tb10x_pinfuncgrp *pfg = &state->pingroups[i]; + unsigned int port = pfg->port; + unsigned int mode = pfg->mode; + int j; + + /* + * Skip pin groups which are always mapped and don't need + * to be configured. + */ + if (port < 0) + continue; + + for (j = 0; j < pfg->pincnt; j++) { + if (pin == pfg->pins[j]) { + if (pfg->isgpio) { + /* + * Remember the GPIO-only setting of + * the port this pin belongs to. + */ + muxport = port; + muxmode = mode; + } else if (state->ports[port].count + && (state->ports[port].mode == mode)) { + /* + * Error: The requested pin is already + * used for something else. + */ + mutex_unlock(&state->mutex); + return -EBUSY; + } + break; + } + } + } + + /* + * If we haven't returned an error at this point, the GPIO pin is not + * used by another function and the GPIO request can be granted: + * Register pin as being used as GPIO so we don't allocate it to + * another function later. + */ + set_bit(pin, state->gpios); + + /* + * Potential conflicts between GPIOs and pin functions were caught + * earlier in this function and tb10x_pinctrl_set_config will do the + * Right Thing, either configure the port in GPIO only mode or leave + * another mode compatible with this GPIO request untouched. + */ + if (muxport >= 0) + tb10x_pinctrl_set_config(state, muxport, muxmode); + + mutex_unlock(&state->mutex); + + return 0; +} + +static void tb10x_gpio_disable_free(struct pinctrl_dev *pctl, + struct pinctrl_gpio_range *range, + unsigned pin) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + + mutex_lock(&state->mutex); + + clear_bit(pin, state->gpios); + + mutex_unlock(&state->mutex); +} + +static int tb10x_pctl_enable(struct pinctrl_dev *pctl, + unsigned func_selector, unsigned group_selector) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector]; + int i; + + if (grp->port < 0) + return 0; + + mutex_lock(&state->mutex); + + /* + * Check if the requested function is compatible with previously + * requested functions. + */ + if (state->ports[grp->port].count + && (state->ports[grp->port].mode != grp->mode)) { + mutex_unlock(&state->mutex); + return -EBUSY; + } + + /* + * Check if the requested function is compatible with previously + * requested GPIOs. + */ + for (i = 0; i < grp->pincnt; i++) + if (test_bit(grp->pins[i], state->gpios)) { + mutex_unlock(&state->mutex); + return -EBUSY; + } + + tb10x_pinctrl_set_config(state, grp->port, grp->mode); + + state->ports[grp->port].count++; + + mutex_unlock(&state->mutex); + + return 0; +} + +static void tb10x_pctl_disable(struct pinctrl_dev *pctl, + unsigned func_selector, unsigned group_selector) +{ + struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); + const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector]; + + if (grp->port < 0) + return; + + mutex_lock(&state->mutex); + + state->ports[grp->port].count--; + + mutex_unlock(&state->mutex); +} + +static struct pinmux_ops tb10x_pinmux_ops = { + .get_functions_count = tb10x_get_functions_count, + .get_function_name = tb10x_get_function_name, + .get_function_groups = tb10x_get_function_groups, + .gpio_request_enable = tb10x_gpio_request_enable, + .gpio_disable_free = tb10x_gpio_disable_free, + .enable = tb10x_pctl_enable, + .disable = tb10x_pctl_disable, +}; + +static struct pinctrl_desc tb10x_pindesc = { + .name = "TB10x", + .pins = tb10x_pins, + .npins = ARRAY_SIZE(tb10x_pins), + .owner = THIS_MODULE, + .pctlops = &tb10x_pinctrl_ops, + .pmxops = &tb10x_pinmux_ops, +}; + +static int tb10x_pinctrl_probe(struct platform_device *pdev) +{ + int ret = -EINVAL; + struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct device *dev = &pdev->dev; + struct device_node *of_node = dev->of_node; + struct device_node *child; + struct tb10x_pinctrl *state; + int i; + + if (!of_node) { + dev_err(dev, "No device tree node found.\n"); + return -EINVAL; + } + + if (!mem) { + dev_err(dev, "No memory resource defined.\n"); + return -EINVAL; + } + + state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) + + of_get_child_count(of_node) + * sizeof(struct tb10x_of_pinfunc), + GFP_KERNEL); + if (!state) + return -ENOMEM; + + platform_set_drvdata(pdev, state); + state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1); + mutex_init(&state->mutex); + + state->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(state->base)) { + ret = PTR_ERR(state->base); + goto fail; + } + + state->pingroups = tb10x_pingroups; + state->pinfuncgrpcnt = ARRAY_SIZE(tb10x_pingroups); + + for (i = 0; i < TB10X_PORTS; i++) + state->ports[i].mode = tb10x_pinctrl_get_config(state, i); + + for_each_child_of_node(of_node, child) { + const char *name; + + if (!of_property_read_string(child, "abilis,function", + &name)) { + state->pinfuncs[state->pinfuncnt].name = child->name; + state->pinfuncs[state->pinfuncnt].group = name; + state->pinfuncnt++; + } + } + + state->pctl = pinctrl_register(&tb10x_pindesc, dev, state); + if (!state->pctl) { + dev_err(dev, "could not register TB10x pin driver\n"); + ret = -EINVAL; + goto fail; + } + + return 0; + +fail: + mutex_destroy(&state->mutex); + return ret; +} + +static int tb10x_pinctrl_remove(struct platform_device *pdev) +{ + struct tb10x_pinctrl *state = platform_get_drvdata(pdev); + + pinctrl_unregister(state->pctl); + mutex_destroy(&state->mutex); + + return 0; +} + + +static const struct of_device_id tb10x_pinctrl_dt_ids[] = { + { .compatible = "abilis,tb10x-iomux" }, + { } +}; +MODULE_DEVICE_TABLE(of, tb10x_pinctrl_dt_ids); + +static struct platform_driver tb10x_pinctrl_pdrv = { + .probe = tb10x_pinctrl_probe, + .remove = tb10x_pinctrl_remove, + .driver = { + .name = "tb10x_pinctrl", + .of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids), + .owner = THIS_MODULE + } +}; + +module_platform_driver(tb10x_pinctrl_pdrv); + +MODULE_AUTHOR("Christian Ruppert <christian.ruppert@abilis.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-vf610.c b/drivers/pinctrl/pinctrl-vf610.c index 68a970b1dbc..bddd913d28b 100644 --- a/drivers/pinctrl/pinctrl-vf610.c +++ b/drivers/pinctrl/pinctrl-vf610.c @@ -316,7 +316,7 @@ static struct platform_driver vf610_pinctrl_driver = { .driver = { .name = "vf610-pinctrl", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(vf610_pinctrl_of_match), + .of_match_table = vf610_pinctrl_of_match, }, .probe = vf610_pinctrl_probe, .remove = imx_pinctrl_remove, diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9d144a263dc..9248ce4efed 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -505,16 +505,14 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) pin_free(pctldev, pins[i], NULL); } else { const char *gname; - const char *pname; - pname = desc ? desc->name : "non-existing"; gname = pctlops->get_group_name(pctldev, setting->data.mux.group); dev_warn(pctldev->dev, "not freeing pin %d (%s) as part of " "deactivating group %s - it is already " "used for some other setting", - pins[i], pname, gname); + pins[i], desc->name, gname); } } diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig index 636a882b406..26187aa5cf5 100644 --- a/drivers/pinctrl/sh-pfc/Kconfig +++ b/drivers/pinctrl/sh-pfc/Kconfig @@ -45,6 +45,11 @@ config PINCTRL_PFC_R8A7790 depends on ARCH_R8A7790 select PINCTRL_SH_PFC +config PINCTRL_PFC_R8A7791 + def_bool y + depends on ARCH_R8A7791 + select PINCTRL_SH_PFC + config PINCTRL_PFC_SH7203 def_bool y depends on CPU_SUBTYPE_SH7203 diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile index 5e0c222c12d..ad8f4cf9faa 100644 --- a/drivers/pinctrl/sh-pfc/Makefile +++ b/drivers/pinctrl/sh-pfc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o obj-$(CONFIG_PINCTRL_PFC_R8A7779) += pfc-r8a7779.o obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o +obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 738f14f65cf..d77ece5217f 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -431,6 +431,12 @@ static const struct of_device_id sh_pfc_of_table[] = { .data = &r8a7790_pinmux_info, }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A7791 + { + .compatible = "renesas,pfc-r8a7791", + .data = &r8a7791_pinmux_info, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_SH7372 { .compatible = "renesas,pfc-sh7372", @@ -558,6 +564,9 @@ static const struct platform_device_id sh_pfc_id_table[] = { #ifdef CONFIG_PINCTRL_PFC_R8A7790 { "pfc-r8a7790", (kernel_ulong_t)&r8a7790_pinmux_info }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A7791 + { "pfc-r8a7791", (kernel_ulong_t)&r8a7791_pinmux_info }, +#endif #ifdef CONFIG_PINCTRL_PFC_SH7203 { "pfc-sh7203", (kernel_ulong_t)&sh7203_pinmux_info }, #endif diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h index a1b23762ac9..11ea8726865 100644 --- a/drivers/pinctrl/sh-pfc/core.h +++ b/drivers/pinctrl/sh-pfc/core.h @@ -69,6 +69,7 @@ extern const struct sh_pfc_soc_info r8a7740_pinmux_info; extern const struct sh_pfc_soc_info r8a7778_pinmux_info; extern const struct sh_pfc_soc_info r8a7779_pinmux_info; extern const struct sh_pfc_soc_info r8a7790_pinmux_info; +extern const struct sh_pfc_soc_info r8a7791_pinmux_info; extern const struct sh_pfc_soc_info sh7203_pinmux_info; extern const struct sh_pfc_soc_info sh7264_pinmux_info; extern const struct sh_pfc_soc_info sh7269_pinmux_info; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c index 428d2a6857e..8b1881c2059 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c @@ -1288,6 +1288,49 @@ static struct sh_pfc_pin pinmux_pins[] = { arg5##_MARK, arg6##_MARK, \ arg7##_MARK, arg8##_MARK, } +/* - AUDIO macro -------------------------------------------------------------*/ +#define AUDIO_PFC_PIN(name, pin) SH_PFC_PINS(name, pin) +#define AUDIO_PFC_DAT(name, pin) SH_PFC_MUX1(name, pin) + +/* - AUDIO clock -------------------------------------------------------------*/ +AUDIO_PFC_PIN(audio_clk_a, RCAR_GP_PIN(2, 22)); +AUDIO_PFC_DAT(audio_clk_a, AUDIO_CLKA); +AUDIO_PFC_PIN(audio_clk_b, RCAR_GP_PIN(2, 23)); +AUDIO_PFC_DAT(audio_clk_b, AUDIO_CLKB); +AUDIO_PFC_PIN(audio_clk_c, RCAR_GP_PIN(2, 7)); +AUDIO_PFC_DAT(audio_clk_c, AUDIO_CLKC); +AUDIO_PFC_PIN(audio_clkout_a, RCAR_GP_PIN(2, 16)); +AUDIO_PFC_DAT(audio_clkout_a, AUDIO_CLKOUT_A); +AUDIO_PFC_PIN(audio_clkout_b, RCAR_GP_PIN(1, 16)); +AUDIO_PFC_DAT(audio_clkout_b, AUDIO_CLKOUT_B); + +/* - CAN macro --------_----------------------------------------------------- */ +#define CAN_PFC_PINS(name, args...) SH_PFC_PINS(name, args) +#define CAN_PFC_DATA(name, tx, rx) SH_PFC_MUX2(name, tx, rx) +#define CAN_PFC_CLK(name, clk) SH_PFC_MUX1(name, clk) + +/* - CAN0 ------------------------------------------------------------------- */ +CAN_PFC_PINS(can0_data_a, RCAR_GP_PIN(1, 30), RCAR_GP_PIN(1, 31)); +CAN_PFC_DATA(can0_data_a, CAN0_TX_A, CAN0_RX_A); +CAN_PFC_PINS(can0_data_b, RCAR_GP_PIN(2, 26), RCAR_GP_PIN(2, 27)); +CAN_PFC_DATA(can0_data_b, CAN0_TX_B, CAN0_RX_B); + +/* - CAN1 ------------------------------------------------------------------- */ +CAN_PFC_PINS(can1_data_a, RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 19)); +CAN_PFC_DATA(can1_data_a, CAN1_TX_A, CAN1_RX_A); +CAN_PFC_PINS(can1_data_b, RCAR_GP_PIN(2, 28), RCAR_GP_PIN(2, 29)); +CAN_PFC_DATA(can1_data_b, CAN1_TX_B, CAN1_RX_B); + +/* - CAN_CLK --------------------------------------------------------------- */ +CAN_PFC_PINS(can_clk_a, RCAR_GP_PIN(3, 24)); +CAN_PFC_CLK(can_clk_a, CAN_CLK_A); +CAN_PFC_PINS(can_clk_b, RCAR_GP_PIN(1, 16)); +CAN_PFC_CLK(can_clk_b, CAN_CLK_B); +CAN_PFC_PINS(can_clk_c, RCAR_GP_PIN(4, 24)); +CAN_PFC_CLK(can_clk_c, CAN_CLK_C); +CAN_PFC_PINS(can_clk_d, RCAR_GP_PIN(2, 25)); +CAN_PFC_CLK(can_clk_d, CAN_CLK_D); + /* - Ether ------------------------------------------------------------------ */ SH_PFC_PINS(ether_rmii, RCAR_GP_PIN(4, 10), RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 9), @@ -1577,6 +1620,59 @@ SDHI_PFC_WPPN(sdhi2_wp_a, SD2_WP_A); SDHI_PFC_PINS(sdhi2_wp_b, RCAR_GP_PIN(3, 28)); SDHI_PFC_WPPN(sdhi2_wp_b, SD2_WP_B); +/* - SSI macro -------------------------------------------------------------- */ +#define SSI_PFC_PINS(name, args...) SH_PFC_PINS(name, args) +#define SSI_PFC_CTRL(name, sck, ws) SH_PFC_MUX2(name, sck, ws) +#define SSI_PFC_DATA(name, d) SH_PFC_MUX1(name, d) + +/* - SSI 0/1/2 -------------------------------------------------------------- */ +SSI_PFC_PINS(ssi012_ctrl, RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7)); +SSI_PFC_CTRL(ssi012_ctrl, SSI_SCK012, SSI_WS012); +SSI_PFC_PINS(ssi0_data, RCAR_GP_PIN(3, 10)); +SSI_PFC_DATA(ssi0_data, SSI_SDATA0); +SSI_PFC_PINS(ssi1_a_ctrl, RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 21)); +SSI_PFC_CTRL(ssi1_a_ctrl, SSI_SCK1_A, SSI_WS1_A); +SSI_PFC_PINS(ssi1_b_ctrl, PIN_NUMBER(3, 20), RCAR_GP_PIN(1, 3)); +SSI_PFC_CTRL(ssi1_b_ctrl, SSI_SCK1_B, SSI_WS1_B); +SSI_PFC_PINS(ssi1_data, RCAR_GP_PIN(3, 9)); +SSI_PFC_DATA(ssi1_data, SSI_SDATA1); +SSI_PFC_PINS(ssi2_a_ctrl, RCAR_GP_PIN(2, 26), RCAR_GP_PIN(3, 4)); +SSI_PFC_CTRL(ssi2_a_ctrl, SSI_SCK2_A, SSI_WS2_A); +SSI_PFC_PINS(ssi2_b_ctrl, RCAR_GP_PIN(2, 6), RCAR_GP_PIN(2, 17)); +SSI_PFC_CTRL(ssi2_b_ctrl, SSI_SCK2_B, SSI_WS2_B); +SSI_PFC_PINS(ssi2_data, RCAR_GP_PIN(3, 8)); +SSI_PFC_DATA(ssi2_data, SSI_SDATA2); + +/* - SSI 3/4 ---------------------------------------------------------------- */ +SSI_PFC_PINS(ssi34_ctrl, RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3)); +SSI_PFC_CTRL(ssi34_ctrl, SSI_SCK34, SSI_WS34); +SSI_PFC_PINS(ssi3_data, RCAR_GP_PIN(3, 5)); +SSI_PFC_DATA(ssi3_data, SSI_SDATA3); +SSI_PFC_PINS(ssi4_ctrl, RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 23)); +SSI_PFC_CTRL(ssi4_ctrl, SSI_SCK4, SSI_WS4); +SSI_PFC_PINS(ssi4_data, RCAR_GP_PIN(3, 4)); +SSI_PFC_DATA(ssi4_data, SSI_SDATA4); + +/* - SSI 5 ------------------------------------------------------------------ */ +SSI_PFC_PINS(ssi5_ctrl, RCAR_GP_PIN(2, 31), RCAR_GP_PIN(3, 0)); +SSI_PFC_CTRL(ssi5_ctrl, SSI_SCK5, SSI_WS5); +SSI_PFC_PINS(ssi5_data, RCAR_GP_PIN(3, 1)); +SSI_PFC_DATA(ssi5_data, SSI_SDATA5); + +/* - SSI 6 ------------------------------------------------------------------ */ +SSI_PFC_PINS(ssi6_ctrl, RCAR_GP_PIN(2, 28), RCAR_GP_PIN(2, 29)); +SSI_PFC_CTRL(ssi6_ctrl, SSI_SCK6, SSI_WS6); +SSI_PFC_PINS(ssi6_data, RCAR_GP_PIN(2, 30)); +SSI_PFC_DATA(ssi6_data, SSI_SDATA6); + +/* - SSI 7/8 --------------------------------------------------------------- */ +SSI_PFC_PINS(ssi78_ctrl, RCAR_GP_PIN(2, 24), RCAR_GP_PIN(2, 25)); +SSI_PFC_CTRL(ssi78_ctrl, SSI_SCK78, SSI_WS78); +SSI_PFC_PINS(ssi7_data, RCAR_GP_PIN(2, 27)); +SSI_PFC_DATA(ssi7_data, SSI_SDATA7); +SSI_PFC_PINS(ssi8_data, RCAR_GP_PIN(2, 26)); +SSI_PFC_DATA(ssi8_data, SSI_SDATA8); + /* - USB0 ------------------------------------------------------------------- */ SH_PFC_PINS(usb0, RCAR_GP_PIN(0, 1)); SH_PFC_MUX1(usb0, PENC0); @@ -1624,6 +1720,19 @@ VIN_PFC_PINS(vin1_sync, RCAR_GP_PIN(3, 21), RCAR_GP_PIN(3, 22)); VIN_PFC_SYNC(vin1_sync, VI1_HSYNC, VI1_VSYNC); static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(audio_clk_a), + SH_PFC_PIN_GROUP(audio_clk_b), + SH_PFC_PIN_GROUP(audio_clk_c), + SH_PFC_PIN_GROUP(audio_clkout_a), + SH_PFC_PIN_GROUP(audio_clkout_b), + SH_PFC_PIN_GROUP(can0_data_a), + SH_PFC_PIN_GROUP(can0_data_b), + SH_PFC_PIN_GROUP(can1_data_a), + SH_PFC_PIN_GROUP(can1_data_b), + SH_PFC_PIN_GROUP(can_clk_a), + SH_PFC_PIN_GROUP(can_clk_b), + SH_PFC_PIN_GROUP(can_clk_c), + SH_PFC_PIN_GROUP(can_clk_d), SH_PFC_PIN_GROUP(ether_rmii), SH_PFC_PIN_GROUP(ether_link), SH_PFC_PIN_GROUP(ether_magic), @@ -1713,6 +1822,25 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(sdhi2_data4_b), SH_PFC_PIN_GROUP(sdhi2_wp_a), SH_PFC_PIN_GROUP(sdhi2_wp_b), + SH_PFC_PIN_GROUP(ssi012_ctrl), + SH_PFC_PIN_GROUP(ssi0_data), + SH_PFC_PIN_GROUP(ssi1_a_ctrl), + SH_PFC_PIN_GROUP(ssi1_b_ctrl), + SH_PFC_PIN_GROUP(ssi1_data), + SH_PFC_PIN_GROUP(ssi2_a_ctrl), + SH_PFC_PIN_GROUP(ssi2_b_ctrl), + SH_PFC_PIN_GROUP(ssi2_data), + SH_PFC_PIN_GROUP(ssi34_ctrl), + SH_PFC_PIN_GROUP(ssi3_data), + SH_PFC_PIN_GROUP(ssi4_ctrl), + SH_PFC_PIN_GROUP(ssi4_data), + SH_PFC_PIN_GROUP(ssi5_ctrl), + SH_PFC_PIN_GROUP(ssi5_data), + SH_PFC_PIN_GROUP(ssi6_ctrl), + SH_PFC_PIN_GROUP(ssi6_data), + SH_PFC_PIN_GROUP(ssi78_ctrl), + SH_PFC_PIN_GROUP(ssi7_data), + SH_PFC_PIN_GROUP(ssi8_data), SH_PFC_PIN_GROUP(usb0), SH_PFC_PIN_GROUP(usb0_ovc), SH_PFC_PIN_GROUP(usb1), @@ -1725,6 +1853,32 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(vin1_sync), }; +static const char * const audio_clk_groups[] = { + "audio_clk_a", + "audio_clk_b", + "audio_clk_c", + "audio_clkout_a", + "audio_clkout_b", +}; + +static const char * const can0_groups[] = { + "can0_data_a", + "can0_data_b", + "can_clk_a", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + +static const char * const can1_groups[] = { + "can1_data_a", + "can1_data_b", + "can_clk_a", + "can_clk_b", + "can_clk_c", + "can_clk_d", +}; + static const char * const ether_groups[] = { "ether_rmii", "ether_link", @@ -1875,6 +2029,28 @@ static const char * const sdhi2_groups[] = { "sdhi2_wp_b", }; +static const char * const ssi_groups[] = { + "ssi012_ctrl", + "ssi0_data", + "ssi1_a_ctrl", + "ssi1_b_ctrl", + "ssi1_data", + "ssi2_a_ctrl", + "ssi2_b_ctrl", + "ssi2_data", + "ssi34_ctrl", + "ssi3_data", + "ssi4_ctrl", + "ssi4_data", + "ssi5_ctrl", + "ssi5_data", + "ssi6_ctrl", + "ssi6_data", + "ssi78_ctrl", + "ssi7_data", + "ssi8_data", +}; + static const char * const usb0_groups[] = { "usb0", "usb0_ovc", @@ -1898,6 +2074,9 @@ static const char * const vin1_groups[] = { }; static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(audio_clk), + SH_PFC_FUNCTION(can0), + SH_PFC_FUNCTION(can1), SH_PFC_FUNCTION(ether), SH_PFC_FUNCTION(hscif0), SH_PFC_FUNCTION(hscif1), @@ -1918,6 +2097,7 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi0), SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(ssi), SH_PFC_FUNCTION(usb0), SH_PFC_FUNCTION(usb1), SH_PFC_FUNCTION(vin0), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index 64fcc00693b..72786fc9395 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -781,6 +781,8 @@ enum { ADICS_SAMP_MARK, DU2_CDE_MARK, QPOLB_MARK, SCIFA2_RXD_B_MARK, USB1_PWEN_MARK, AUDIO_CLKOUT_D_MARK, USB1_OVC_MARK, TCLK1_B_MARK, + + I2C3_SCL_MARK, I2C3_SDA_MARK, PINMUX_MARK_END, }; @@ -1719,10 +1721,22 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_DATA(IP16_6, AUDIO_CLKOUT_D), PINMUX_IPSR_DATA(IP16_7, USB1_OVC), PINMUX_IPSR_MODSEL_DATA(IP16_7, TCLK1_B, SEL_TMU1_1), + + PINMUX_DATA(I2C3_SCL_MARK, FN_SEL_IICDVFS_1), + PINMUX_DATA(I2C3_SDA_MARK, FN_SEL_IICDVFS_1), }; +/* R8A7790 has 6 banks with 32 GPIOs in each = 192 GPIOs */ +#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r)) +#define PIN_NUMBER(r, c) (((r) - 'A') * 31 + (c) + 200) +#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c) + static struct sh_pfc_pin pinmux_pins[] = { PINMUX_GPIO_GP_ALL(), + + /* Pins not associated with a GPIO port */ + SH_PFC_PIN_NAMED(ROW_GROUP_A('J'), 15, AJ15), + SH_PFC_PIN_NAMED(ROW_GROUP_A('H'), 15, AH15), }; /* - DU RGB ----------------------------------------------------------------- */ @@ -1990,6 +2004,72 @@ static const unsigned int hscif1_ctrl_b_pins[] = { static const unsigned int hscif1_ctrl_b_mux[] = { HRTS1_N_B_MARK, HCTS1_N_B_MARK, }; +/* - I2C1 ------------------------------------------------------------------- */ +static const unsigned int i2c1_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(1, 16), RCAR_GP_PIN(1, 17), +}; +static const unsigned int i2c1_mux[] = { + I2C1_SCL_MARK, I2C1_SDA_MARK, +}; +static const unsigned int i2c1_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7), +}; +static const unsigned int i2c1_b_mux[] = { + I2C1_SCL_B_MARK, I2C1_SDA_B_MARK, +}; +static const unsigned int i2c1_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 27), +}; +static const unsigned int i2c1_c_mux[] = { + I2C1_SCL_C_MARK, I2C1_SDA_C_MARK, +}; +/* - I2C2 ------------------------------------------------------------------- */ +static const unsigned int i2c2_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6), +}; +static const unsigned int i2c2_mux[] = { + I2C2_SCL_MARK, I2C2_SDA_MARK, +}; +static const unsigned int i2c2_b_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), +}; +static const unsigned int i2c2_b_mux[] = { + I2C2_SCL_B_MARK, I2C2_SDA_B_MARK, +}; +static const unsigned int i2c2_c_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(0, 6), RCAR_GP_PIN(0, 7), +}; +static const unsigned int i2c2_c_mux[] = { + I2C2_SCL_C_MARK, I2C2_SDA_C_MARK, +}; +static const unsigned int i2c2_d_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15), +}; +static const unsigned int i2c2_d_mux[] = { + I2C2_SCL_D_MARK, I2C2_SDA_D_MARK, +}; +static const unsigned int i2c2_e_pins[] = { + /* SCL, SDA */ + RCAR_GP_PIN(2, 18), RCAR_GP_PIN(2, 19), +}; +static const unsigned int i2c2_e_mux[] = { + I2C2_SCL_E_MARK, I2C2_SDA_E_MARK, +}; +/* - I2C3 ------------------------------------------------------------------- */ +static const unsigned int i2c3_pins[] = { + /* SCL, SDA */ + PIN_A_NUMBER('J', 15), PIN_A_NUMBER('H', 15), +}; +static const unsigned int i2c3_mux[] = { + I2C3_SCL_MARK, I2C3_SDA_MARK, +}; /* - INTC ------------------------------------------------------------------- */ static const unsigned int intc_irq0_pins[] = { /* IRQ */ @@ -3047,6 +3127,15 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(hscif1_data_b), SH_PFC_PIN_GROUP(hscif1_clk_b), SH_PFC_PIN_GROUP(hscif1_ctrl_b), + SH_PFC_PIN_GROUP(i2c1), + SH_PFC_PIN_GROUP(i2c1_b), + SH_PFC_PIN_GROUP(i2c1_c), + SH_PFC_PIN_GROUP(i2c2), + SH_PFC_PIN_GROUP(i2c2_b), + SH_PFC_PIN_GROUP(i2c2_c), + SH_PFC_PIN_GROUP(i2c2_d), + SH_PFC_PIN_GROUP(i2c2_e), + SH_PFC_PIN_GROUP(i2c3), SH_PFC_PIN_GROUP(intc_irq0), SH_PFC_PIN_GROUP(intc_irq1), SH_PFC_PIN_GROUP(intc_irq2), @@ -3243,6 +3332,24 @@ static const char * const hscif1_groups[] = { "hscif1_ctrl_b", }; +static const char * const i2c1_groups[] = { + "i2c1", + "i2c1_b", + "i2c1_c", +}; + +static const char * const i2c2_groups[] = { + "i2c2", + "i2c2_b", + "i2c2_c", + "i2c2_d", + "i2c2_e", +}; + +static const char * const i2c3_groups[] = { + "i2c3", +}; + static const char * const intc_groups[] = { "intc_irq0", "intc_irq1", @@ -3469,6 +3576,9 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(eth), SH_PFC_FUNCTION(hscif0), SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(i2c1), + SH_PFC_FUNCTION(i2c2), + SH_PFC_FUNCTION(i2c3), SH_PFC_FUNCTION(intc), SH_PFC_FUNCTION(mmc0), SH_PFC_FUNCTION(mmc1), diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c new file mode 100644 index 00000000000..bf76a654c02 --- /dev/null +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -0,0 +1,4214 @@ +/* + * r8a7791 processor support - PFC hardware block. + * + * Copyright (C) 2013 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/platform_data/gpio-rcar.h> + +#include "core.h" +#include "sh_pfc.h" + +#define CPU_ALL_PORT(fn, sfx) \ + PORT_GP_32(0, fn, sfx), \ + PORT_GP_32(1, fn, sfx), \ + PORT_GP_32(2, fn, sfx), \ + PORT_GP_32(3, fn, sfx), \ + PORT_GP_32(4, fn, sfx), \ + PORT_GP_32(5, fn, sfx), \ + PORT_GP_32(6, fn, sfx), \ + PORT_GP_32(7, fn, sfx) + +enum { + PINMUX_RESERVED = 0, + + PINMUX_DATA_BEGIN, + GP_ALL(DATA), + PINMUX_DATA_END, + + PINMUX_FUNCTION_BEGIN, + GP_ALL(FN), + + /* GPSR0 */ + FN_IP0_0, FN_IP0_1, FN_IP0_2, FN_IP0_3, FN_IP0_4, FN_IP0_5, + FN_IP0_6, FN_IP0_7, FN_IP0_8, FN_IP0_9, FN_IP0_10, FN_IP0_11, + FN_IP0_12, FN_IP0_13, FN_IP0_14, FN_IP0_15, FN_IP0_18_16, FN_IP0_20_19, + FN_IP0_22_21, FN_IP0_24_23, FN_IP0_26_25, FN_IP0_28_27, FN_IP0_30_29, + FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4, FN_IP1_7_6, FN_IP1_10_8, + FN_IP1_13_11, FN_IP1_16_14, FN_IP1_19_17, FN_IP1_22_20, + + /* GPSR1 */ + FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0, FN_IP2_4_3, + FN_IP2_6_5, FN_IP2_9_7, FN_IP2_12_10, FN_IP2_15_13, FN_IP2_18_16, + FN_IP2_20_19, FN_IP2_22_21, FN_EX_CS0_N, FN_IP2_24_23, FN_IP2_26_25, + FN_IP2_29_27, FN_IP3_2_0, FN_IP3_5_3, FN_IP3_8_6, FN_RD_N, + FN_IP3_11_9, FN_IP3_13_12, FN_IP3_15_14 , FN_IP3_17_16 , FN_IP3_19_18, + FN_IP3_21_20, + + /* GPSR2 */ + FN_IP3_27_25, FN_IP3_30_28, FN_IP4_1_0, FN_IP4_4_2, FN_IP4_7_5, + FN_IP4_9_8, FN_IP4_12_10, FN_IP4_15_13, FN_IP4_18_16, FN_IP4_19, + FN_IP4_20, FN_IP4_21, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26, + FN_IP4_30_28, FN_IP5_2_0, FN_IP5_5_3, FN_IP5_8_6, FN_IP5_11_9, + FN_IP5_14_12, FN_IP5_16_15, FN_IP5_19_17, FN_IP5_21_20, FN_IP5_23_22, + FN_IP5_25_24, FN_IP5_28_26, FN_IP5_31_29, FN_AUDIO_CLKA, FN_IP6_2_0, + FN_IP6_5_3, FN_IP6_7_6, + + /* GPSR3 */ + FN_IP7_5_3, FN_IP7_8_6, FN_IP7_10_9, FN_IP7_12_11, FN_IP7_14_13, + FN_IP7_16_15, FN_IP7_18_17, FN_IP7_20_19, FN_IP7_23_21, FN_IP7_26_24, + FN_IP7_29_27, FN_IP8_2_0, FN_IP8_5_3, FN_IP8_8_6, FN_IP8_11_9, + FN_IP8_14_12, FN_IP8_17_15, FN_IP8_20_18, FN_IP8_23_21, FN_IP8_25_24, + FN_IP8_27_26, FN_IP8_30_28, FN_IP9_2_0, FN_IP9_5_3, FN_IP9_6, FN_IP9_7, + FN_IP9_10_8, FN_IP9_11, FN_IP9_12, FN_IP9_15_13, FN_IP9_16, + FN_IP9_18_17, + + /* GPSR4 */ + FN_VI0_CLK, FN_IP9_20_19, FN_IP9_22_21, FN_IP9_24_23, FN_IP9_26_25, + FN_VI0_DATA0_VI0_B0, FN_VI0_DATA1_VI0_B1, FN_VI0_DATA2_VI0_B2, + FN_IP9_28_27, FN_VI0_DATA4_VI0_B4, FN_VI0_DATA5_VI0_B5, + FN_VI0_DATA6_VI0_B6, FN_VI0_DATA7_VI0_B7, FN_IP9_31_29, FN_IP10_2_0, + FN_IP10_5_3, FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_16_15, + FN_IP10_18_17, FN_IP10_21_19, FN_IP10_24_22, FN_IP10_26_25, + FN_IP10_28_27, FN_IP10_31_29, FN_IP11_2_0, FN_IP11_5_3, FN_IP11_8_6, + FN_IP15_1_0, FN_IP15_3_2, FN_IP15_5_4, + + /* GPSR5 */ + FN_IP11_11_9, FN_IP11_14_12, FN_IP11_16_15, FN_IP11_18_17, FN_IP11_19, + FN_IP11_20, FN_IP11_21, FN_IP11_22, FN_IP11_23, FN_IP11_24, + FN_IP11_25, FN_IP11_26, FN_IP11_27, FN_IP11_29_28, FN_IP11_31_30, + FN_IP12_1_0, FN_IP12_3_2, FN_IP12_6_4, FN_IP12_9_7, FN_IP12_12_10, + FN_IP12_15_13, FN_IP12_17_16, FN_IP12_19_18, FN_IP12_21_20, + FN_IP12_23_22, FN_IP12_26_24, FN_IP12_29_27, FN_IP13_2_0, FN_IP13_4_3, + FN_IP13_6_5, FN_IP13_9_7, FN_IP3_24_22, + + /* GPSR6 */ + FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14, + FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23, + FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0, + FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7, + FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17, + FN_IP14_22_20, FN_IP14_25_23, FN_IP14_28_26, FN_IP14_31_29, + FN_USB1_OVC, FN_DU0_DOTCLKIN, + + /* GPSR7 */ + FN_IP15_17_15, FN_IP15_20_18, FN_IP15_23_21, FN_IP15_26_24, + FN_IP15_29_27, FN_IP16_2_0, FN_IP16_5_3, FN_IP16_7_6, FN_IP16_9_8, + FN_IP16_11_10, FN_IP6_9_8, FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, + FN_IP6_18_16, FN_IP6_20_19, FN_IP6_23_21, FN_IP6_26_24, FN_IP6_29_27, + FN_IP7_2_0, FN_IP15_8_6, FN_IP15_11_9, FN_IP15_14_12, + FN_USB0_PWEN, FN_USB0_OVC, FN_USB1_PWEN, + + /* IPSR0 */ + FN_D0, FN_D1, FN_D2, FN_D3, FN_D4, FN_D5, FN_D6, FN_D7, FN_D8, + FN_D9, FN_D10, FN_D11, FN_D12, FN_D13, FN_D14, FN_D15, + FN_A0, FN_ATAWR0_N_C, FN_MSIOF0_SCK_B, FN_SCL0_C, FN_PWM2_B, + FN_A1, FN_MSIOF0_SYNC_B, FN_A2, FN_MSIOF0_SS1_B, + FN_A3, FN_MSIOF0_SS2_B, FN_A4, FN_MSIOF0_TXD_B, + FN_A5, FN_MSIOF0_RXD_B, FN_A6, FN_MSIOF1_SCK, + + /* IPSR1 */ + FN_A7, FN_MSIOF1_SYNC, FN_A8, FN_MSIOF1_SS1, FN_SCL0, + FN_A9, FN_MSIOF1_SS2, FN_SDA0, + FN_A10, FN_MSIOF1_TXD, FN_MSIOF1_TXD_D, + FN_A11, FN_MSIOF1_RXD, FN_SCL3_D, FN_MSIOF1_RXD_D, + FN_A12, FN_FMCLK, FN_SDA3_D, FN_MSIOF1_SCK_D, + FN_A13, FN_ATAG0_N_C, FN_BPFCLK, FN_MSIOF1_SS1_D, + FN_A14, FN_ATADIR0_N_C, FN_FMIN, FN_FMIN_C, FN_MSIOF1_SYNC_D, + FN_A15, FN_BPFCLK_C, + FN_A16, FN_DREQ2_B, FN_FMCLK_C, FN_SCIFA1_SCK_B, + FN_A17, FN_DACK2_B, FN_SDA0_C, + FN_A18, FN_DREQ1, FN_SCIFA1_RXD_C, FN_SCIFB1_RXD_C, + + /* IPSR2 */ + FN_A19, FN_DACK1, FN_SCIFA1_TXD_C, FN_SCIFB1_TXD_C, FN_SCIFB1_SCK_B, + FN_A20, FN_SPCLK, + FN_A21, FN_ATAWR0_N_B, FN_MOSI_IO0, + FN_A22, FN_MISO_IO1, FN_FMCLK_B, FN_TX0, FN_SCIFA0_TXD, + FN_A23, FN_IO2, FN_BPFCLK_B, FN_RX0, FN_SCIFA0_RXD, + FN_A24, FN_DREQ2, FN_IO3, FN_TX1, FN_SCIFA1_TXD, + FN_A25, FN_DACK2, FN_SSL, FN_DREQ1_C, FN_RX1, FN_SCIFA1_RXD, + FN_CS0_N, FN_ATAG0_N_B, FN_SCL1, + FN_CS1_N_A26, FN_ATADIR0_N_B, FN_SDA1, + FN_EX_CS1_N, FN_MSIOF2_SCK, + FN_EX_CS2_N, FN_ATAWR0_N, FN_MSIOF2_SYNC, + FN_EX_CS3_N, FN_ATADIR0_N, FN_MSIOF2_TXD, FN_ATAG0_N, FN_EX_WAIT1, + + /* IPSR3 */ + FN_EX_CS4_N, FN_ATARD0_N, FN_MSIOF2_RXD, FN_EX_WAIT2, + FN_EX_CS5_N, FN_ATACS00_N, FN_MSIOF2_SS1, FN_HRX1_B, + FN_SCIFB1_RXD_B, FN_PWM1, FN_TPU_TO1, + FN_BS_N, FN_ATACS10_N, FN_MSIOF2_SS2, FN_HTX1_B, + FN_SCIFB1_TXD_B, FN_PWM2, FN_TPU_TO2, + FN_RD_WR_N, FN_HRX2_B, FN_FMIN_B, FN_SCIFB0_RXD_B, FN_DREQ1_D, + FN_WE0_N, FN_HCTS2_N_B, FN_SCIFB0_TXD_B, + FN_WE1_N, FN_ATARD0_N_B, FN_HTX2_B, FN_SCIFB0_RTS_N_B, + FN_EX_WAIT0, FN_HRTS2_N_B, FN_SCIFB0_CTS_N_B, + FN_DREQ0, FN_PWM3, FN_TPU_TO3, + FN_DACK0, FN_DRACK0, FN_REMOCON, + FN_SPEEDIN, FN_HSCK0_C, FN_HSCK2_C, FN_SCIFB0_SCK_B, + FN_SCIFB2_SCK_B, FN_DREQ2_C, FN_HTX2_D, + FN_SSI_SCK0129, FN_HRX0_C, FN_HRX2_C, FN_SCIFB0_RXD_C, FN_SCIFB2_RXD_C, + FN_SSI_WS0129, FN_HTX0_C, FN_HTX2_C, FN_SCIFB0_TXD_C, FN_SCIFB2_TXD_C, + + /* IPSR4 */ + FN_SSI_SDATA0, FN_SCL0_B, FN_SCL7_B, FN_MSIOF2_SCK_C, + FN_SSI_SCK1, FN_SDA0_B, FN_SDA7_B, FN_MSIOF2_SYNC_C, FN_GLO_I0_D, + FN_SSI_WS1, FN_SCL1_B, FN_SCL8_B, FN_MSIOF2_TXD_C, FN_GLO_I1_D, + FN_SSI_SDATA1, FN_SDA1_B, FN_SDA8_B, FN_MSIOF2_RXD_C, + FN_SSI_SCK2, FN_SCL2, FN_GPS_CLK_B, FN_GLO_Q0_D, FN_HSCK1_E, + FN_SSI_WS2, FN_SDA2, FN_GPS_SIGN_B, FN_RX2_E, + FN_GLO_Q1_D, FN_HCTS1_N_E, + FN_SSI_SDATA2, FN_GPS_MAG_B, FN_TX2_E, FN_HRTS1_N_E, + FN_SSI_SCK34, FN_SSI_WS34, FN_SSI_SDATA3, + FN_SSI_SCK4, FN_GLO_SS_D, + FN_SSI_WS4, FN_GLO_RFON_D, + FN_SSI_SDATA4, FN_MSIOF2_SCK_D, + FN_SSI_SCK5, FN_MSIOF1_SCK_C, FN_TS_SDATA0, FN_GLO_I0, + FN_MSIOF2_SYNC_D, FN_VI1_R2_B, + + /* IPSR5 */ + FN_SSI_WS5, FN_MSIOF1_SYNC_C, FN_TS_SCK0, FN_GLO_I1, + FN_MSIOF2_TXD_D, FN_VI1_R3_B, + FN_SSI_SDATA5, FN_MSIOF1_TXD_C, FN_TS_SDEN0, FN_GLO_Q0, + FN_MSIOF2_SS1_D, FN_VI1_R4_B, + FN_SSI_SCK6, FN_MSIOF1_RXD_C, FN_TS_SPSYNC0, FN_GLO_Q1, + FN_MSIOF2_RXD_D, FN_VI1_R5_B, + FN_SSI_WS6, FN_GLO_SCLK, FN_MSIOF2_SS2_D, FN_VI1_R6_B, + FN_SSI_SDATA6, FN_STP_IVCXO27_0_B, FN_GLO_SDATA, FN_VI1_R7_B, + FN_SSI_SCK78, FN_STP_ISCLK_0_B, FN_GLO_SS, + FN_SSI_WS78, FN_TX0_D, FN_STP_ISD_0_B, FN_GLO_RFON, + FN_SSI_SDATA7, FN_RX0_D, FN_STP_ISEN_0_B, + FN_SSI_SDATA8, FN_TX1_D, FN_STP_ISSYNC_0_B, + FN_SSI_SCK9, FN_RX1_D, FN_GLO_SCLK_D, + FN_SSI_WS9, FN_TX3_D, FN_CAN0_TX_D, FN_GLO_SDATA_D, + FN_SSI_SDATA9, FN_RX3_D, FN_CAN0_RX_D, + + /* IPSR6 */ + FN_AUDIO_CLKB, FN_STP_OPWM_0_B, FN_MSIOF1_SCK_B, + FN_SCIF_CLK, FN_BPFCLK_E, + FN_AUDIO_CLKC, FN_SCIFB0_SCK_C, FN_MSIOF1_SYNC_B, FN_RX2, + FN_SCIFA2_RXD, FN_FMIN_E, + FN_AUDIO_CLKOUT, FN_MSIOF1_SS1_B, FN_TX2, FN_SCIFA2_TXD, + FN_IRQ0, FN_SCIFB1_RXD_D, FN_INTC_IRQ0_N, + FN_IRQ1, FN_SCIFB1_SCK_C, FN_INTC_IRQ1_N, + FN_IRQ2, FN_SCIFB1_TXD_D, FN_INTC_IRQ2_N, + FN_IRQ3, FN_SCL4_C, FN_MSIOF2_TXD_E, FN_INTC_IRQ3_N, + FN_IRQ4, FN_HRX1_C, FN_SDA4_C, FN_MSIOF2_RXD_E, FN_INTC_IRQ4_N, + FN_IRQ5, FN_HTX1_C, FN_SCL1_E, FN_MSIOF2_SCK_E, + FN_IRQ6, FN_HSCK1_C, FN_MSIOF1_SS2_B, FN_SDA1_E, FN_MSIOF2_SYNC_E, + FN_IRQ7, FN_HCTS1_N_C, FN_MSIOF1_TXD_B, FN_GPS_CLK_C, FN_GPS_CLK_D, + FN_IRQ8, FN_HRTS1_N_C, FN_MSIOF1_RXD_B, FN_GPS_SIGN_C, FN_GPS_SIGN_D, + + /* IPSR7 */ + FN_IRQ9, FN_DU1_DOTCLKIN_B, FN_CAN_CLK_D, FN_GPS_MAG_C, + FN_SCIF_CLK_B, FN_GPS_MAG_D, + FN_DU1_DR0, FN_LCDOUT0, FN_VI1_DATA0_B, FN_TX0_B, + FN_SCIFA0_TXD_B, FN_MSIOF2_SCK_B, + FN_DU1_DR1, FN_LCDOUT1, FN_VI1_DATA1_B, FN_RX0_B, + FN_SCIFA0_RXD_B, FN_MSIOF2_SYNC_B, + FN_DU1_DR2, FN_LCDOUT2, FN_SSI_SCK0129_B, + FN_DU1_DR3, FN_LCDOUT3, FN_SSI_WS0129_B, + FN_DU1_DR4, FN_LCDOUT4, FN_SSI_SDATA0_B, + FN_DU1_DR5, FN_LCDOUT5, FN_SSI_SCK1_B, + FN_DU1_DR6, FN_LCDOUT6, FN_SSI_WS1_B, + FN_DU1_DR7, FN_LCDOUT7, FN_SSI_SDATA1_B, + FN_DU1_DG0, FN_LCDOUT8, FN_VI1_DATA2_B, FN_TX1_B, + FN_SCIFA1_TXD_B, FN_MSIOF2_SS1_B, + FN_DU1_DG1, FN_LCDOUT9, FN_VI1_DATA3_B, FN_RX1_B, + FN_SCIFA1_RXD_B, FN_MSIOF2_SS2_B, + FN_DU1_DG2, FN_LCDOUT10, FN_VI1_DATA4_B, FN_SCIF1_SCK_B, + FN_SCIFA1_SCK, FN_SSI_SCK78_B, + + /* IPSR8 */ + FN_DU1_DG3, FN_LCDOUT11, FN_VI1_DATA5_B, FN_SSI_WS78_B, + FN_DU1_DG4, FN_LCDOUT12, FN_VI1_DATA6_B, FN_HRX0_B, + FN_SCIFB2_RXD_B, FN_SSI_SDATA7_B, + FN_DU1_DG5, FN_LCDOUT13, FN_VI1_DATA7_B, FN_HCTS0_N_B, + FN_SCIFB2_TXD_B, FN_SSI_SDATA8_B, + FN_DU1_DG6, FN_LCDOUT14, FN_HRTS0_N_B, + FN_SCIFB2_CTS_N_B, FN_SSI_SCK9_B, + FN_DU1_DG7, FN_LCDOUT15, FN_HTX0_B, FN_SCIFB2_RTS_N_B, FN_SSI_WS9_B, + FN_DU1_DB0, FN_LCDOUT16, FN_VI1_CLK_B, FN_TX2_B, + FN_SCIFA2_TXD_B, FN_MSIOF2_TXD_B, + FN_DU1_DB1, FN_LCDOUT17, FN_VI1_HSYNC_N_B, FN_RX2_B, + FN_SCIFA2_RXD_B, FN_MSIOF2_RXD_B, + FN_DU1_DB2, FN_LCDOUT18, FN_VI1_VSYNC_N_B, FN_SCIF2_SCK_B, + FN_SCIFA2_SCK, FN_SSI_SDATA9_B, + FN_DU1_DB3, FN_LCDOUT19, FN_VI1_CLKENB_B, + FN_DU1_DB4, FN_LCDOUT20, FN_VI1_FIELD_B, FN_CAN1_RX, + FN_DU1_DB5, FN_LCDOUT21, FN_TX3, FN_SCIFA3_TXD, FN_CAN1_TX, + + /* IPSR9 */ + FN_DU1_DB6, FN_LCDOUT22, FN_SCL3_C, FN_RX3, FN_SCIFA3_RXD, + FN_DU1_DB7, FN_LCDOUT23, FN_SDA3_C, FN_SCIF3_SCK, FN_SCIFA3_SCK, + FN_DU1_DOTCLKIN, FN_QSTVA_QVS, + FN_DU1_DOTCLKOUT0, FN_QCLK, + FN_DU1_DOTCLKOUT1, FN_QSTVB_QVE, FN_CAN0_TX, + FN_TX3_B, FN_SCL2_B, FN_PWM4, + FN_DU1_EXHSYNC_DU1_HSYNC, FN_QSTH_QHS, + FN_DU1_EXVSYNC_DU1_VSYNC, FN_QSTB_QHE, + FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_QCPV_QDE, + FN_CAN0_RX, FN_RX3_B, FN_SDA2_B, + FN_DU1_DISP, FN_QPOLA, + FN_DU1_CDE, FN_QPOLB, FN_PWM4_B, + FN_VI0_CLKENB, FN_TX4, FN_SCIFA4_TXD, FN_TS_SDATA0_D, + FN_VI0_FIELD, FN_RX4, FN_SCIFA4_RXD, FN_TS_SCK0_D, + FN_VI0_HSYNC_N, FN_TX5, FN_SCIFA5_TXD, FN_TS_SDEN0_D, + FN_VI0_VSYNC_N, FN_RX5, FN_SCIFA5_RXD, FN_TS_SPSYNC0_D, + FN_VI0_DATA3_VI0_B3, FN_SCIF3_SCK_B, FN_SCIFA3_SCK_B, + FN_VI0_G0, FN_SCL8, FN_STP_IVCXO27_0_C, FN_SCL4, + FN_HCTS2_N, FN_SCIFB2_CTS_N, FN_ATAWR1_N, + + /* IPSR10 */ + FN_VI0_G1, FN_SDA8, FN_STP_ISCLK_0_C, FN_SDA4, + FN_HRTS2_N, FN_SCIFB2_RTS_N, FN_ATADIR1_N, + FN_VI0_G2, FN_VI2_HSYNC_N, FN_STP_ISD_0_C, FN_SCL3_B, + FN_HSCK2, FN_SCIFB2_SCK, FN_ATARD1_N, + FN_VI0_G3, FN_VI2_VSYNC_N, FN_STP_ISEN_0_C, FN_SDA3_B, + FN_HRX2, FN_SCIFB2_RXD, FN_ATACS01_N, + FN_VI0_G4, FN_VI2_CLKENB, FN_STP_ISSYNC_0_C, + FN_HTX2, FN_SCIFB2_TXD, FN_SCIFB0_SCK_D, + FN_VI0_G5, FN_VI2_FIELD, FN_STP_OPWM_0_C, FN_FMCLK_D, + FN_CAN0_TX_E, FN_HTX1_D, FN_SCIFB0_TXD_D, + FN_VI0_G6, FN_VI2_CLK, FN_BPFCLK_D, + FN_VI0_G7, FN_VI2_DATA0, FN_FMIN_D, + FN_VI0_R0, FN_VI2_DATA1, FN_GLO_I0_B, + FN_TS_SDATA0_C, FN_ATACS11_N, + FN_VI0_R1, FN_VI2_DATA2, FN_GLO_I1_B, + FN_TS_SCK0_C, FN_ATAG1_N, + FN_VI0_R2, FN_VI2_DATA3, FN_GLO_Q0_B, FN_TS_SDEN0_C, + FN_VI0_R3, FN_VI2_DATA4, FN_GLO_Q1_B, FN_TS_SPSYNC0_C, + FN_VI0_R4, FN_VI2_DATA5, FN_GLO_SCLK_B, FN_TX0_C, FN_SCL1_D, + + /* IPSR11 */ + FN_VI0_R5, FN_VI2_DATA6, FN_GLO_SDATA_B, FN_RX0_C, FN_SDA1_D, + FN_VI0_R6, FN_VI2_DATA7, FN_GLO_SS_B, FN_TX1_C, FN_SCL4_B, + FN_VI0_R7, FN_GLO_RFON_B, FN_RX1_C, FN_CAN0_RX_E, + FN_SDA4_B, FN_HRX1_D, FN_SCIFB0_RXD_D, + FN_VI1_HSYNC_N, FN_AVB_RXD0, FN_TS_SDATA0_B, FN_TX4_B, FN_SCIFA4_TXD_B, + FN_VI1_VSYNC_N, FN_AVB_RXD1, FN_TS_SCK0_B, FN_RX4_B, FN_SCIFA4_RXD_B, + FN_VI1_CLKENB, FN_AVB_RXD2, FN_TS_SDEN0_B, + FN_VI1_FIELD, FN_AVB_RXD3, FN_TS_SPSYNC0_B, + FN_VI1_CLK, FN_AVB_RXD4, FN_VI1_DATA0, FN_AVB_RXD5, + FN_VI1_DATA1, FN_AVB_RXD6, FN_VI1_DATA2, FN_AVB_RXD7, + FN_VI1_DATA3, FN_AVB_RX_ER, FN_VI1_DATA4, FN_AVB_MDIO, + FN_VI1_DATA5, FN_AVB_RX_DV, FN_VI1_DATA6, FN_AVB_MAGIC, + FN_VI1_DATA7, FN_AVB_MDC, + FN_ETH_MDIO, FN_AVB_RX_CLK, FN_SCL2_C, + FN_ETH_CRS_DV, FN_AVB_LINK, FN_SDA2_C, + + /* IPSR12 */ + FN_ETH_RX_ER, FN_AVB_CRS, FN_SCL3, FN_SCL7, + FN_ETH_RXD0, FN_AVB_PHY_INT, FN_SDA3, FN_SDA7, + FN_ETH_RXD1, FN_AVB_GTXREFCLK, FN_CAN0_TX_C, + FN_SCL2_D, FN_MSIOF1_RXD_E, + FN_ETH_LINK, FN_AVB_TXD0, FN_CAN0_RX_C, FN_SDA2_D, FN_MSIOF1_SCK_E, + FN_ETH_REFCLK, FN_AVB_TXD1, FN_SCIFA3_RXD_B, + FN_CAN1_RX_C, FN_MSIOF1_SYNC_E, + FN_ETH_TXD1, FN_AVB_TXD2, FN_SCIFA3_TXD_B, + FN_CAN1_TX_C, FN_MSIOF1_TXD_E, + FN_ETH_TX_EN, FN_AVB_TXD3, FN_TCLK1_B, FN_CAN_CLK_B, + FN_ETH_MAGIC, FN_AVB_TXD4, FN_IETX_C, + FN_ETH_TXD0, FN_AVB_TXD5, FN_IECLK_C, + FN_ETH_MDC, FN_AVB_TXD6, FN_IERX_C, + FN_STP_IVCXO27_0, FN_AVB_TXD7, FN_SCIFB2_TXD_D, + FN_ADIDATA_B, FN_MSIOF0_SYNC_C, + FN_STP_ISCLK_0, FN_AVB_TX_EN, FN_SCIFB2_RXD_D, + FN_ADICS_SAMP_B, FN_MSIOF0_SCK_C, + + /* IPSR13 */ + FN_STP_ISD_0, FN_AVB_TX_ER, FN_SCIFB2_SCK_C, + FN_ADICLK_B, FN_MSIOF0_SS1_C, + FN_STP_ISEN_0, FN_AVB_TX_CLK, FN_ADICHS0_B, FN_MSIOF0_SS2_C, + FN_STP_ISSYNC_0, FN_AVB_COL, FN_ADICHS1_B, FN_MSIOF0_RXD_C, + FN_STP_OPWM_0, FN_AVB_GTX_CLK, FN_PWM0_B, + FN_ADICHS2_B, FN_MSIOF0_TXD_C, + FN_SD0_CLK, FN_SPCLK_B, FN_SD0_CMD, FN_MOSI_IO0_B, + FN_SD0_DATA0, FN_MISO_IO1_B, FN_SD0_DATA1, FN_IO2_B, + FN_SD0_DATA2, FN_IO3_B, FN_SD0_DATA3, FN_SSL_B, + FN_SD0_CD, FN_MMC_D6_B, FN_SIM0_RST_B, FN_CAN0_RX_F, + FN_SCIFA5_TXD_B, FN_TX3_C, + FN_SD0_WP, FN_MMC_D7_B, FN_SIM0_D_B, FN_CAN0_TX_F, + FN_SCIFA5_RXD_B, FN_RX3_C, + FN_SD1_CMD, FN_REMOCON_B, FN_SD1_DATA0, FN_SPEEDIN_B, + FN_SD1_DATA1, FN_IETX_B, FN_SD1_DATA2, FN_IECLK_B, + FN_SD1_DATA3, FN_IERX_B, + FN_SD1_CD, FN_PWM0, FN_TPU_TO0, FN_SCL1_C, + + /* IPSR14 */ + FN_SD1_WP, FN_PWM1_B, FN_SDA1_C, + FN_SD2_CLK, FN_MMC_CLK, FN_SD2_CMD, FN_MMC_CMD, + FN_SD2_DATA0, FN_MMC_D0, FN_SD2_DATA1, FN_MMC_D1, + FN_SD2_DATA2, FN_MMC_D2, FN_SD2_DATA3, FN_MMC_D3, + FN_SD2_CD, FN_MMC_D4, FN_SCL8_C, FN_TX5_B, FN_SCIFA5_TXD_C, + FN_SD2_WP, FN_MMC_D5, FN_SDA8_C, FN_RX5_B, FN_SCIFA5_RXD_C, + FN_MSIOF0_SCK, FN_RX2_C, FN_ADIDATA, FN_VI1_CLK_C, FN_VI1_G0_B, + FN_MSIOF0_SYNC, FN_TX2_C, FN_ADICS_SAMP, FN_VI1_CLKENB_C, FN_VI1_G1_B, + FN_MSIOF0_TXD, FN_ADICLK, FN_VI1_FIELD_C, FN_VI1_G2_B, + FN_MSIOF0_RXD, FN_ADICHS0, FN_VI1_DATA0_C, FN_VI1_G3_B, + FN_MSIOF0_SS1, FN_MMC_D6, FN_ADICHS1, FN_TX0_E, + FN_VI1_HSYNC_N_C, FN_SCL7_C, FN_VI1_G4_B, + FN_MSIOF0_SS2, FN_MMC_D7, FN_ADICHS2, FN_RX0_E, + FN_VI1_VSYNC_N_C, FN_SDA7_C, FN_VI1_G5_B, + + /* IPSR15 */ + FN_SIM0_RST, FN_IETX, FN_CAN1_TX_D, + FN_SIM0_CLK, FN_IECLK, FN_CAN_CLK_C, + FN_SIM0_D, FN_IERX, FN_CAN1_RX_D, + FN_GPS_CLK, FN_DU1_DOTCLKIN_C, FN_AUDIO_CLKB_B, + FN_PWM5_B, FN_SCIFA3_TXD_C, + FN_GPS_SIGN, FN_TX4_C, FN_SCIFA4_TXD_C, FN_PWM5, + FN_VI1_G6_B, FN_SCIFA3_RXD_C, + FN_GPS_MAG, FN_RX4_C, FN_SCIFA4_RXD_C, FN_PWM6, + FN_VI1_G7_B, FN_SCIFA3_SCK_C, + FN_HCTS0_N, FN_SCIFB0_CTS_N, FN_GLO_I0_C, FN_TCLK1, FN_VI1_DATA1_C, + FN_HRTS0_N, FN_SCIFB0_RTS_N, FN_GLO_I1_C, FN_VI1_DATA2_C, + FN_HSCK0, FN_SCIFB0_SCK, FN_GLO_Q0_C, FN_CAN_CLK, + FN_TCLK2, FN_VI1_DATA3_C, + FN_HRX0, FN_SCIFB0_RXD, FN_GLO_Q1_C, FN_CAN0_RX_B, FN_VI1_DATA4_C, + FN_HTX0, FN_SCIFB0_TXD, FN_GLO_SCLK_C, FN_CAN0_TX_B, FN_VI1_DATA5_C, + + /* IPSR16 */ + FN_HRX1, FN_SCIFB1_RXD, FN_VI1_R0_B, FN_GLO_SDATA_C, FN_VI1_DATA6_C, + FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B, FN_GLO_SS_C, FN_VI1_DATA7_C, + FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C, + FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B, + FN_HRTS1_N, FN_SCIFB1_RTS_N, FN_MLB_DAT, FN_CAN1_RX_B, + + /* MOD_SEL */ + FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3, + FN_SEL_SCIFB_0, FN_SEL_SCIFB_1, FN_SEL_SCIFB_2, FN_SEL_SCIFB_3, + FN_SEL_SCIFB2_0, FN_SEL_SCIFB2_1, FN_SEL_SCIFB2_2, FN_SEL_SCIFB2_3, + FN_SEL_SCIFB1_0, FN_SEL_SCIFB1_1, FN_SEL_SCIFB1_2, FN_SEL_SCIFB1_3, + FN_SEL_SCIFA1_0, FN_SEL_SCIFA1_1, FN_SEL_SCIFA1_2, + FN_SEL_SSI9_0, FN_SEL_SSI9_1, + FN_SEL_SCFA_0, FN_SEL_SCFA_1, + FN_SEL_QSP_0, FN_SEL_QSP_1, + FN_SEL_SSI7_0, FN_SEL_SSI7_1, + FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1, FN_SEL_HSCIF1_2, FN_SEL_HSCIF1_3, + FN_SEL_HSCIF1_4, + FN_SEL_VI1_0, FN_SEL_VI1_1, FN_SEL_VI1_2, + FN_SEL_TMU1_0, FN_SEL_TMU1_1, + FN_SEL_LBS_0, FN_SEL_LBS_1, FN_SEL_LBS_2, FN_SEL_LBS_3, + FN_SEL_TSIF0_0, FN_SEL_TSIF0_1, FN_SEL_TSIF0_2, FN_SEL_TSIF0_3, + FN_SEL_SOF0_0, FN_SEL_SOF0_1, FN_SEL_SOF0_2, + + /* MOD_SEL2 */ + FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, FN_SEL_SCIF0_3, + FN_SEL_SCIF0_4, + FN_SEL_SCIF_0, FN_SEL_SCIF_1, + FN_SEL_CAN0_0, FN_SEL_CAN0_1, FN_SEL_CAN0_2, FN_SEL_CAN0_3, + FN_SEL_CAN0_4, FN_SEL_CAN0_5, + FN_SEL_CAN1_0, FN_SEL_CAN1_1, FN_SEL_CAN1_2, FN_SEL_CAN1_3, + FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1, + FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, + FN_SEL_ADG_0, FN_SEL_ADG_1, + FN_SEL_FM_0, FN_SEL_FM_1, FN_SEL_FM_2, FN_SEL_FM_3, FN_SEL_FM_4, + FN_SEL_SCIFA5_0, FN_SEL_SCIFA5_1, FN_SEL_SCIFA5_2, + FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, FN_SEL_GPS_3, + FN_SEL_SCIFA4_0, FN_SEL_SCIFA4_1, FN_SEL_SCIFA4_2, + FN_SEL_SCIFA3_0, FN_SEL_SCIFA3_1, FN_SEL_SCIFA3_2, + FN_SEL_SIM_0, FN_SEL_SIM_1, + FN_SEL_SSI8_0, FN_SEL_SSI8_1, + + /* MOD_SEL3 */ + FN_SEL_HSCIF2_0, FN_SEL_HSCIF2_1, FN_SEL_HSCIF2_2, FN_SEL_HSCIF2_3, + FN_SEL_CANCLK_0, FN_SEL_CANCLK_1, FN_SEL_CANCLK_2, FN_SEL_CANCLK_3, + FN_SEL_IIC8_0, FN_SEL_IIC8_1, FN_SEL_IIC8_2, + FN_SEL_IIC7_0, FN_SEL_IIC7_1, FN_SEL_IIC7_2, + FN_SEL_IIC4_0, FN_SEL_IIC4_1, FN_SEL_IIC4_2, + FN_SEL_IIC3_0, FN_SEL_IIC3_1, FN_SEL_IIC3_2, FN_SEL_IIC3_3, + FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3, + FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2, + FN_SEL_MMC_0, FN_SEL_MMC_1, + FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, + FN_SEL_IIC2_0, FN_SEL_IIC2_1, FN_SEL_IIC2_2, FN_SEL_IIC2_3, + FN_SEL_IIC1_0, FN_SEL_IIC1_1, FN_SEL_IIC1_2, FN_SEL_IIC1_3, + FN_SEL_IIC1_4, + FN_SEL_IIC0_0, FN_SEL_IIC0_1, FN_SEL_IIC0_2, + + /* MOD_SEL4 */ + FN_SEL_SOF1_0, FN_SEL_SOF1_1, FN_SEL_SOF1_2, FN_SEL_SOF1_3, + FN_SEL_SOF1_4, + FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1, FN_SEL_HSCIF0_2, + FN_SEL_DIS_0, FN_SEL_DIS_1, FN_SEL_DIS_2, + FN_SEL_RAD_0, FN_SEL_RAD_1, + FN_SEL_RCN_0, FN_SEL_RCN_1, + FN_SEL_RSP_0, FN_SEL_RSP_1, + FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3, + FN_SEL_SCIF2_4, + FN_SEL_SOF2_0, FN_SEL_SOF2_1, FN_SEL_SOF2_2, FN_SEL_SOF2_3, + FN_SEL_SOF2_4, + FN_SEL_SSI1_0, FN_SEL_SSI1_1, + FN_SEL_SSI0_0, FN_SEL_SSI0_1, + FN_SEL_SSP_0, FN_SEL_SSP_1, FN_SEL_SSP_2, + PINMUX_FUNCTION_END, + + PINMUX_MARK_BEGIN, + + EX_CS0_N_MARK, RD_N_MARK, + + AUDIO_CLKA_MARK, + + VI0_CLK_MARK, VI0_DATA0_VI0_B0_MARK, VI0_DATA1_VI0_B1_MARK, + VI0_DATA2_VI0_B2_MARK, VI0_DATA4_VI0_B4_MARK, VI0_DATA5_VI0_B5_MARK, + VI0_DATA6_VI0_B6_MARK, VI0_DATA7_VI0_B7_MARK, + + SD1_CLK_MARK, + + USB0_PWEN_MARK, USB0_OVC_MARK, USB1_PWEN_MARK, USB1_OVC_MARK, + DU0_DOTCLKIN_MARK, + + /* IPSR0 */ + D0_MARK, D1_MARK, D2_MARK, D3_MARK, D4_MARK, D5_MARK, + D6_MARK, D7_MARK, D8_MARK, + D9_MARK, D10_MARK, D11_MARK, D12_MARK, D13_MARK, D14_MARK, D15_MARK, + A0_MARK, ATAWR0_N_C_MARK, MSIOF0_SCK_B_MARK, SCL0_C_MARK, PWM2_B_MARK, + A1_MARK, MSIOF0_SYNC_B_MARK, A2_MARK, MSIOF0_SS1_B_MARK, + A3_MARK, MSIOF0_SS2_B_MARK, A4_MARK, MSIOF0_TXD_B_MARK, + A5_MARK, MSIOF0_RXD_B_MARK, A6_MARK, MSIOF1_SCK_MARK, + + /* IPSR1 */ + A7_MARK, MSIOF1_SYNC_MARK, A8_MARK, MSIOF1_SS1_MARK, SCL0_MARK, + A9_MARK, MSIOF1_SS2_MARK, SDA0_MARK, + A10_MARK, MSIOF1_TXD_MARK, MSIOF1_TXD_D_MARK, + A11_MARK, MSIOF1_RXD_MARK, SCL3_D_MARK, MSIOF1_RXD_D_MARK, + A12_MARK, FMCLK_MARK, SDA3_D_MARK, MSIOF1_SCK_D_MARK, + A13_MARK, ATAG0_N_C_MARK, BPFCLK_MARK, MSIOF1_SS1_D_MARK, + A14_MARK, ATADIR0_N_C_MARK, FMIN_MARK, FMIN_C_MARK, MSIOF1_SYNC_D_MARK, + A15_MARK, BPFCLK_C_MARK, + A16_MARK, DREQ2_B_MARK, FMCLK_C_MARK, SCIFA1_SCK_B_MARK, + A17_MARK, DACK2_B_MARK, SDA0_C_MARK, + A18_MARK, DREQ1_MARK, SCIFA1_RXD_C_MARK, SCIFB1_RXD_C_MARK, + + /* IPSR2 */ + A19_MARK, DACK1_MARK, SCIFA1_TXD_C_MARK, + SCIFB1_TXD_C_MARK, SCIFB1_SCK_B_MARK, + A20_MARK, SPCLK_MARK, + A21_MARK, ATAWR0_N_B_MARK, MOSI_IO0_MARK, + A22_MARK, MISO_IO1_MARK, FMCLK_B_MARK, TX0_MARK, SCIFA0_TXD_MARK, + A23_MARK, IO2_MARK, BPFCLK_B_MARK, RX0_MARK, SCIFA0_RXD_MARK, + A24_MARK, DREQ2_MARK, IO3_MARK, TX1_MARK, SCIFA1_TXD_MARK, + A25_MARK, DACK2_MARK, SSL_MARK, DREQ1_C_MARK, + RX1_MARK, SCIFA1_RXD_MARK, + CS0_N_MARK, ATAG0_N_B_MARK, SCL1_MARK, + CS1_N_A26_MARK, ATADIR0_N_B_MARK, SDA1_MARK, + EX_CS1_N_MARK, MSIOF2_SCK_MARK, + EX_CS2_N_MARK, ATAWR0_N_MARK, MSIOF2_SYNC_MARK, + EX_CS3_N_MARK, ATADIR0_N_MARK, MSIOF2_TXD_MARK, + ATAG0_N_MARK, EX_WAIT1_MARK, + + /* IPSR3 */ + EX_CS4_N_MARK, ATARD0_N_MARK, MSIOF2_RXD_MARK, EX_WAIT2_MARK, + EX_CS5_N_MARK, ATACS00_N_MARK, MSIOF2_SS1_MARK, HRX1_B_MARK, + SCIFB1_RXD_B_MARK, PWM1_MARK, TPU_TO1_MARK, + BS_N_MARK, ATACS10_N_MARK, MSIOF2_SS2_MARK, HTX1_B_MARK, + SCIFB1_TXD_B_MARK, PWM2_MARK, TPU_TO2_MARK, + RD_WR_N_MARK, HRX2_B_MARK, FMIN_B_MARK, + SCIFB0_RXD_B_MARK, DREQ1_D_MARK, + WE0_N_MARK, HCTS2_N_B_MARK, SCIFB0_TXD_B_MARK, + WE1_N_MARK, ATARD0_N_B_MARK, HTX2_B_MARK, SCIFB0_RTS_N_B_MARK, + EX_WAIT0_MARK, HRTS2_N_B_MARK, SCIFB0_CTS_N_B_MARK, + DREQ0_MARK, PWM3_MARK, TPU_TO3_MARK, + DACK0_MARK, DRACK0_MARK, REMOCON_MARK, + SPEEDIN_MARK, HSCK0_C_MARK, HSCK2_C_MARK, SCIFB0_SCK_B_MARK, + SCIFB2_SCK_B_MARK, DREQ2_C_MARK, HTX2_D_MARK, + SSI_SCK0129_MARK, HRX0_C_MARK, HRX2_C_MARK, + SCIFB0_RXD_C_MARK, SCIFB2_RXD_C_MARK, + SSI_WS0129_MARK, HTX0_C_MARK, HTX2_C_MARK, + SCIFB0_TXD_C_MARK, SCIFB2_TXD_C_MARK, + + /* IPSR4 */ + SSI_SDATA0_MARK, SCL0_B_MARK, SCL7_B_MARK, MSIOF2_SCK_C_MARK, + SSI_SCK1_MARK, SDA0_B_MARK, SDA7_B_MARK, + MSIOF2_SYNC_C_MARK, GLO_I0_D_MARK, + SSI_WS1_MARK, SCL1_B_MARK, SCL8_B_MARK, + MSIOF2_TXD_C_MARK, GLO_I1_D_MARK, + SSI_SDATA1_MARK, SDA1_B_MARK, SDA8_B_MARK, MSIOF2_RXD_C_MARK, + SSI_SCK2_MARK, SCL2_MARK, GPS_CLK_B_MARK, GLO_Q0_D_MARK, HSCK1_E_MARK, + SSI_WS2_MARK, SDA2_MARK, GPS_SIGN_B_MARK, RX2_E_MARK, + GLO_Q1_D_MARK, HCTS1_N_E_MARK, + SSI_SDATA2_MARK, GPS_MAG_B_MARK, TX2_E_MARK, HRTS1_N_E_MARK, + SSI_SCK34_MARK, SSI_WS34_MARK, SSI_SDATA3_MARK, + SSI_SCK4_MARK, GLO_SS_D_MARK, + SSI_WS4_MARK, GLO_RFON_D_MARK, + SSI_SDATA4_MARK, MSIOF2_SCK_D_MARK, + SSI_SCK5_MARK, MSIOF1_SCK_C_MARK, TS_SDATA0_MARK, GLO_I0_MARK, + MSIOF2_SYNC_D_MARK, VI1_R2_B_MARK, + + /* IPSR5 */ + SSI_WS5_MARK, MSIOF1_SYNC_C_MARK, TS_SCK0_MARK, GLO_I1_MARK, + MSIOF2_TXD_D_MARK, VI1_R3_B_MARK, + SSI_SDATA5_MARK, MSIOF1_TXD_C_MARK, TS_SDEN0_MARK, GLO_Q0_MARK, + MSIOF2_SS1_D_MARK, VI1_R4_B_MARK, + SSI_SCK6_MARK, MSIOF1_RXD_C_MARK, TS_SPSYNC0_MARK, GLO_Q1_MARK, + MSIOF2_RXD_D_MARK, VI1_R5_B_MARK, + SSI_WS6_MARK, GLO_SCLK_MARK, MSIOF2_SS2_D_MARK, VI1_R6_B_MARK, + SSI_SDATA6_MARK, STP_IVCXO27_0_B_MARK, GLO_SDATA_MARK, VI1_R7_B_MARK, + SSI_SCK78_MARK, STP_ISCLK_0_B_MARK, GLO_SS_MARK, + SSI_WS78_MARK, TX0_D_MARK, STP_ISD_0_B_MARK, GLO_RFON_MARK, + SSI_SDATA7_MARK, RX0_D_MARK, STP_ISEN_0_B_MARK, + SSI_SDATA8_MARK, TX1_D_MARK, STP_ISSYNC_0_B_MARK, + SSI_SCK9_MARK, RX1_D_MARK, GLO_SCLK_D_MARK, + SSI_WS9_MARK, TX3_D_MARK, CAN0_TX_D_MARK, GLO_SDATA_D_MARK, + SSI_SDATA9_MARK, RX3_D_MARK, CAN0_RX_D_MARK, + + /* IPSR6 */ + AUDIO_CLKB_MARK, STP_OPWM_0_B_MARK, MSIOF1_SCK_B_MARK, + SCIF_CLK_MARK, BPFCLK_E_MARK, + AUDIO_CLKC_MARK, SCIFB0_SCK_C_MARK, MSIOF1_SYNC_B_MARK, RX2_MARK, + SCIFA2_RXD_MARK, FMIN_E_MARK, + AUDIO_CLKOUT_MARK, MSIOF1_SS1_B_MARK, TX2_MARK, SCIFA2_TXD_MARK, + IRQ0_MARK, SCIFB1_RXD_D_MARK, INTC_IRQ0_N_MARK, + IRQ1_MARK, SCIFB1_SCK_C_MARK, INTC_IRQ1_N_MARK, + IRQ2_MARK, SCIFB1_TXD_D_MARK, INTC_IRQ2_N_MARK, + IRQ3_MARK, SCL4_C_MARK, MSIOF2_TXD_E_MARK, INTC_IRQ3_N_MARK, + IRQ4_MARK, HRX1_C_MARK, SDA4_C_MARK, + MSIOF2_RXD_E_MARK, INTC_IRQ4_N_MARK, + IRQ5_MARK, HTX1_C_MARK, SCL1_E_MARK, MSIOF2_SCK_E_MARK, + IRQ6_MARK, HSCK1_C_MARK, MSIOF1_SS2_B_MARK, + SDA1_E_MARK, MSIOF2_SYNC_E_MARK, + IRQ7_MARK, HCTS1_N_C_MARK, MSIOF1_TXD_B_MARK, + GPS_CLK_C_MARK, GPS_CLK_D_MARK, + IRQ8_MARK, HRTS1_N_C_MARK, MSIOF1_RXD_B_MARK, + GPS_SIGN_C_MARK, GPS_SIGN_D_MARK, + + /* IPSR7 */ + IRQ9_MARK, DU1_DOTCLKIN_B_MARK, CAN_CLK_D_MARK, GPS_MAG_C_MARK, + SCIF_CLK_B_MARK, GPS_MAG_D_MARK, + DU1_DR0_MARK, LCDOUT0_MARK, VI1_DATA0_B_MARK, TX0_B_MARK, + SCIFA0_TXD_B_MARK, MSIOF2_SCK_B_MARK, + DU1_DR1_MARK, LCDOUT1_MARK, VI1_DATA1_B_MARK, RX0_B_MARK, + SCIFA0_RXD_B_MARK, MSIOF2_SYNC_B_MARK, + DU1_DR2_MARK, LCDOUT2_MARK, SSI_SCK0129_B_MARK, + DU1_DR3_MARK, LCDOUT3_MARK, SSI_WS0129_B_MARK, + DU1_DR4_MARK, LCDOUT4_MARK, SSI_SDATA0_B_MARK, + DU1_DR5_MARK, LCDOUT5_MARK, SSI_SCK1_B_MARK, + DU1_DR6_MARK, LCDOUT6_MARK, SSI_WS1_B_MARK, + DU1_DR7_MARK, LCDOUT7_MARK, SSI_SDATA1_B_MARK, + DU1_DG0_MARK, LCDOUT8_MARK, VI1_DATA2_B_MARK, TX1_B_MARK, + SCIFA1_TXD_B_MARK, MSIOF2_SS1_B_MARK, + DU1_DG1_MARK, LCDOUT9_MARK, VI1_DATA3_B_MARK, RX1_B_MARK, + SCIFA1_RXD_B_MARK, MSIOF2_SS2_B_MARK, + DU1_DG2_MARK, LCDOUT10_MARK, VI1_DATA4_B_MARK, SCIF1_SCK_B_MARK, + SCIFA1_SCK_MARK, SSI_SCK78_B_MARK, + + /* IPSR8 */ + DU1_DG3_MARK, LCDOUT11_MARK, VI1_DATA5_B_MARK, SSI_WS78_B_MARK, + DU1_DG4_MARK, LCDOUT12_MARK, VI1_DATA6_B_MARK, HRX0_B_MARK, + SCIFB2_RXD_B_MARK, SSI_SDATA7_B_MARK, + DU1_DG5_MARK, LCDOUT13_MARK, VI1_DATA7_B_MARK, HCTS0_N_B_MARK, + SCIFB2_TXD_B_MARK, SSI_SDATA8_B_MARK, + DU1_DG6_MARK, LCDOUT14_MARK, HRTS0_N_B_MARK, + SCIFB2_CTS_N_B_MARK, SSI_SCK9_B_MARK, + DU1_DG7_MARK, LCDOUT15_MARK, HTX0_B_MARK, + SCIFB2_RTS_N_B_MARK, SSI_WS9_B_MARK, + DU1_DB0_MARK, LCDOUT16_MARK, VI1_CLK_B_MARK, TX2_B_MARK, + SCIFA2_TXD_B_MARK, MSIOF2_TXD_B_MARK, + DU1_DB1_MARK, LCDOUT17_MARK, VI1_HSYNC_N_B_MARK, RX2_B_MARK, + SCIFA2_RXD_B_MARK, MSIOF2_RXD_B_MARK, + DU1_DB2_MARK, LCDOUT18_MARK, VI1_VSYNC_N_B_MARK, SCIF2_SCK_B_MARK, + SCIFA2_SCK_MARK, SSI_SDATA9_B_MARK, + DU1_DB3_MARK, LCDOUT19_MARK, VI1_CLKENB_B_MARK, + DU1_DB4_MARK, LCDOUT20_MARK, VI1_FIELD_B_MARK, CAN1_RX_MARK, + DU1_DB5_MARK, LCDOUT21_MARK, TX3_MARK, SCIFA3_TXD_MARK, CAN1_TX_MARK, + + /* IPSR9 */ + DU1_DB6_MARK, LCDOUT22_MARK, SCL3_C_MARK, RX3_MARK, SCIFA3_RXD_MARK, + DU1_DB7_MARK, LCDOUT23_MARK, SDA3_C_MARK, + SCIF3_SCK_MARK, SCIFA3_SCK_MARK, + DU1_DOTCLKIN_MARK, QSTVA_QVS_MARK, + DU1_DOTCLKOUT0_MARK, QCLK_MARK, + DU1_DOTCLKOUT1_MARK, QSTVB_QVE_MARK, CAN0_TX_MARK, + TX3_B_MARK, SCL2_B_MARK, PWM4_MARK, + DU1_EXHSYNC_DU1_HSYNC_MARK, QSTH_QHS_MARK, + DU1_EXVSYNC_DU1_VSYNC_MARK, QSTB_QHE_MARK, + DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK, QCPV_QDE_MARK, + CAN0_RX_MARK, RX3_B_MARK, SDA2_B_MARK, + DU1_DISP_MARK, QPOLA_MARK, + DU1_CDE_MARK, QPOLB_MARK, PWM4_B_MARK, + VI0_CLKENB_MARK, TX4_MARK, SCIFA4_TXD_MARK, TS_SDATA0_D_MARK, + VI0_FIELD_MARK, RX4_MARK, SCIFA4_RXD_MARK, TS_SCK0_D_MARK, + VI0_HSYNC_N_MARK, TX5_MARK, SCIFA5_TXD_MARK, TS_SDEN0_D_MARK, + VI0_VSYNC_N_MARK, RX5_MARK, SCIFA5_RXD_MARK, TS_SPSYNC0_D_MARK, + VI0_DATA3_VI0_B3_MARK, SCIF3_SCK_B_MARK, SCIFA3_SCK_B_MARK, + VI0_G0_MARK, SCL8_MARK, STP_IVCXO27_0_C_MARK, SCL4_MARK, + HCTS2_N_MARK, SCIFB2_CTS_N_MARK, ATAWR1_N_MARK, + + /* IPSR10 */ + VI0_G1_MARK, SDA8_MARK, STP_ISCLK_0_C_MARK, SDA4_MARK, + HRTS2_N_MARK, SCIFB2_RTS_N_MARK, ATADIR1_N_MARK, + VI0_G2_MARK, VI2_HSYNC_N_MARK, STP_ISD_0_C_MARK, SCL3_B_MARK, + HSCK2_MARK, SCIFB2_SCK_MARK, ATARD1_N_MARK, + VI0_G3_MARK, VI2_VSYNC_N_MARK, STP_ISEN_0_C_MARK, SDA3_B_MARK, + HRX2_MARK, SCIFB2_RXD_MARK, ATACS01_N_MARK, + VI0_G4_MARK, VI2_CLKENB_MARK, STP_ISSYNC_0_C_MARK, + HTX2_MARK, SCIFB2_TXD_MARK, SCIFB0_SCK_D_MARK, + VI0_G5_MARK, VI2_FIELD_MARK, STP_OPWM_0_C_MARK, FMCLK_D_MARK, + CAN0_TX_E_MARK, HTX1_D_MARK, SCIFB0_TXD_D_MARK, + VI0_G6_MARK, VI2_CLK_MARK, BPFCLK_D_MARK, + VI0_G7_MARK, VI2_DATA0_MARK, FMIN_D_MARK, + VI0_R0_MARK, VI2_DATA1_MARK, GLO_I0_B_MARK, + TS_SDATA0_C_MARK, ATACS11_N_MARK, + VI0_R1_MARK, VI2_DATA2_MARK, GLO_I1_B_MARK, + TS_SCK0_C_MARK, ATAG1_N_MARK, + VI0_R2_MARK, VI2_DATA3_MARK, GLO_Q0_B_MARK, TS_SDEN0_C_MARK, + VI0_R3_MARK, VI2_DATA4_MARK, GLO_Q1_B_MARK, TS_SPSYNC0_C_MARK, + VI0_R4_MARK, VI2_DATA5_MARK, GLO_SCLK_B_MARK, TX0_C_MARK, SCL1_D_MARK, + + /* IPSR11 */ + VI0_R5_MARK, VI2_DATA6_MARK, GLO_SDATA_B_MARK, RX0_C_MARK, SDA1_D_MARK, + VI0_R6_MARK, VI2_DATA7_MARK, GLO_SS_B_MARK, TX1_C_MARK, SCL4_B_MARK, + VI0_R7_MARK, GLO_RFON_B_MARK, RX1_C_MARK, CAN0_RX_E_MARK, + SDA4_B_MARK, HRX1_D_MARK, SCIFB0_RXD_D_MARK, + VI1_HSYNC_N_MARK, AVB_RXD0_MARK, TS_SDATA0_B_MARK, + TX4_B_MARK, SCIFA4_TXD_B_MARK, + VI1_VSYNC_N_MARK, AVB_RXD1_MARK, TS_SCK0_B_MARK, + RX4_B_MARK, SCIFA4_RXD_B_MARK, + VI1_CLKENB_MARK, AVB_RXD2_MARK, TS_SDEN0_B_MARK, + VI1_FIELD_MARK, AVB_RXD3_MARK, TS_SPSYNC0_B_MARK, + VI1_CLK_MARK, AVB_RXD4_MARK, VI1_DATA0_MARK, AVB_RXD5_MARK, + VI1_DATA1_MARK, AVB_RXD6_MARK, VI1_DATA2_MARK, AVB_RXD7_MARK, + VI1_DATA3_MARK, AVB_RX_ER_MARK, VI1_DATA4_MARK, AVB_MDIO_MARK, + VI1_DATA5_MARK, AVB_RX_DV_MARK, VI1_DATA6_MARK, AVB_MAGIC_MARK, + VI1_DATA7_MARK, AVB_MDC_MARK, + ETH_MDIO_MARK, AVB_RX_CLK_MARK, SCL2_C_MARK, + ETH_CRS_DV_MARK, AVB_LINK_MARK, SDA2_C_MARK, + + /* IPSR12 */ + ETH_RX_ER_MARK, AVB_CRS_MARK, SCL3_MARK, SCL7_MARK, + ETH_RXD0_MARK, AVB_PHY_INT_MARK, SDA3_MARK, SDA7_MARK, + ETH_RXD1_MARK, AVB_GTXREFCLK_MARK, CAN0_TX_C_MARK, + SCL2_D_MARK, MSIOF1_RXD_E_MARK, + ETH_LINK_MARK, AVB_TXD0_MARK, CAN0_RX_C_MARK, + SDA2_D_MARK, MSIOF1_SCK_E_MARK, + ETH_REFCLK_MARK, AVB_TXD1_MARK, SCIFA3_RXD_B_MARK, + CAN1_RX_C_MARK, MSIOF1_SYNC_E_MARK, + ETH_TXD1_MARK, AVB_TXD2_MARK, SCIFA3_TXD_B_MARK, + CAN1_TX_C_MARK, MSIOF1_TXD_E_MARK, + ETH_TX_EN_MARK, AVB_TXD3_MARK, TCLK1_B_MARK, CAN_CLK_B_MARK, + ETH_MAGIC_MARK, AVB_TXD4_MARK, IETX_C_MARK, + ETH_TXD0_MARK, AVB_TXD5_MARK, IECLK_C_MARK, + ETH_MDC_MARK, AVB_TXD6_MARK, IERX_C_MARK, + STP_IVCXO27_0_MARK, AVB_TXD7_MARK, SCIFB2_TXD_D_MARK, + ADIDATA_B_MARK, MSIOF0_SYNC_C_MARK, + STP_ISCLK_0_MARK, AVB_TX_EN_MARK, SCIFB2_RXD_D_MARK, + ADICS_SAMP_B_MARK, MSIOF0_SCK_C_MARK, + + /* IPSR13 */ + STP_ISD_0_MARK, AVB_TX_ER_MARK, SCIFB2_SCK_C_MARK, + ADICLK_B_MARK, MSIOF0_SS1_C_MARK, + STP_ISEN_0_MARK, AVB_TX_CLK_MARK, ADICHS0_B_MARK, MSIOF0_SS2_C_MARK, + STP_ISSYNC_0_MARK, AVB_COL_MARK, ADICHS1_B_MARK, MSIOF0_RXD_C_MARK, + STP_OPWM_0_MARK, AVB_GTX_CLK_MARK, PWM0_B_MARK, + ADICHS2_B_MARK, MSIOF0_TXD_C_MARK, + SD0_CLK_MARK, SPCLK_B_MARK, SD0_CMD_MARK, MOSI_IO0_B_MARK, + SD0_DATA0_MARK, MISO_IO1_B_MARK, SD0_DATA1_MARK, IO2_B_MARK, + SD0_DATA2_MARK, IO3_B_MARK, SD0_DATA3_MARK, SSL_B_MARK, + SD0_CD_MARK, MMC_D6_B_MARK, SIM0_RST_B_MARK, CAN0_RX_F_MARK, + SCIFA5_TXD_B_MARK, TX3_C_MARK, + SD0_WP_MARK, MMC_D7_B_MARK, SIM0_D_B_MARK, CAN0_TX_F_MARK, + SCIFA5_RXD_B_MARK, RX3_C_MARK, + SD1_CMD_MARK, REMOCON_B_MARK, SD1_DATA0_MARK, SPEEDIN_B_MARK, + SD1_DATA1_MARK, IETX_B_MARK, SD1_DATA2_MARK, IECLK_B_MARK, + SD1_DATA3_MARK, IERX_B_MARK, + SD1_CD_MARK, PWM0_MARK, TPU_TO0_MARK, SCL1_C_MARK, + + /* IPSR14 */ + SD1_WP_MARK, PWM1_B_MARK, SDA1_C_MARK, + SD2_CLK_MARK, MMC_CLK_MARK, SD2_CMD_MARK, MMC_CMD_MARK, + SD2_DATA0_MARK, MMC_D0_MARK, SD2_DATA1_MARK, MMC_D1_MARK, + SD2_DATA2_MARK, MMC_D2_MARK, SD2_DATA3_MARK, MMC_D3_MARK, + SD2_CD_MARK, MMC_D4_MARK, SCL8_C_MARK, TX5_B_MARK, SCIFA5_TXD_C_MARK, + SD2_WP_MARK, MMC_D5_MARK, SDA8_C_MARK, RX5_B_MARK, SCIFA5_RXD_C_MARK, + MSIOF0_SCK_MARK, RX2_C_MARK, ADIDATA_MARK, + VI1_CLK_C_MARK, VI1_G0_B_MARK, + MSIOF0_SYNC_MARK, TX2_C_MARK, ADICS_SAMP_MARK, + VI1_CLKENB_C_MARK, VI1_G1_B_MARK, + MSIOF0_TXD_MARK, ADICLK_MARK, VI1_FIELD_C_MARK, VI1_G2_B_MARK, + MSIOF0_RXD_MARK, ADICHS0_MARK, VI1_DATA0_C_MARK, VI1_G3_B_MARK, + MSIOF0_SS1_MARK, MMC_D6_MARK, ADICHS1_MARK, TX0_E_MARK, + VI1_HSYNC_N_C_MARK, SCL7_C_MARK, VI1_G4_B_MARK, + MSIOF0_SS2_MARK, MMC_D7_MARK, ADICHS2_MARK, RX0_E_MARK, + VI1_VSYNC_N_C_MARK, SDA7_C_MARK, VI1_G5_B_MARK, + + /* IPSR15 */ + SIM0_RST_MARK, IETX_MARK, CAN1_TX_D_MARK, + SIM0_CLK_MARK, IECLK_MARK, CAN_CLK_C_MARK, + SIM0_D_MARK, IERX_MARK, CAN1_RX_D_MARK, + GPS_CLK_MARK, DU1_DOTCLKIN_C_MARK, AUDIO_CLKB_B_MARK, + PWM5_B_MARK, SCIFA3_TXD_C_MARK, + GPS_SIGN_MARK, TX4_C_MARK, SCIFA4_TXD_C_MARK, PWM5_MARK, + VI1_G6_B_MARK, SCIFA3_RXD_C_MARK, + GPS_MAG_MARK, RX4_C_MARK, SCIFA4_RXD_C_MARK, PWM6_MARK, + VI1_G7_B_MARK, SCIFA3_SCK_C_MARK, + HCTS0_N_MARK, SCIFB0_CTS_N_MARK, GLO_I0_C_MARK, + TCLK1_MARK, VI1_DATA1_C_MARK, + HRTS0_N_MARK, SCIFB0_RTS_N_MARK, GLO_I1_C_MARK, VI1_DATA2_C_MARK, + HSCK0_MARK, SCIFB0_SCK_MARK, GLO_Q0_C_MARK, CAN_CLK_MARK, + TCLK2_MARK, VI1_DATA3_C_MARK, + HRX0_MARK, SCIFB0_RXD_MARK, GLO_Q1_C_MARK, + CAN0_RX_B_MARK, VI1_DATA4_C_MARK, + HTX0_MARK, SCIFB0_TXD_MARK, GLO_SCLK_C_MARK, + CAN0_TX_B_MARK, VI1_DATA5_C_MARK, + + /* IPSR16 */ + HRX1_MARK, SCIFB1_RXD_MARK, VI1_R0_B_MARK, + GLO_SDATA_C_MARK, VI1_DATA6_C_MARK, + HTX1_MARK, SCIFB1_TXD_MARK, VI1_R1_B_MARK, + GLO_SS_C_MARK, VI1_DATA7_C_MARK, + HSCK1_MARK, SCIFB1_SCK_MARK, MLB_CK_MARK, GLO_RFON_C_MARK, + HCTS1_N_MARK, SCIFB1_CTS_N_MARK, MLB_SIG_MARK, CAN1_TX_B_MARK, + HRTS1_N_MARK, SCIFB1_RTS_N_MARK, MLB_DAT_MARK, CAN1_RX_B_MARK, + PINMUX_MARK_END, +}; + +static const u16 pinmux_data[] = { + PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */ + + PINMUX_DATA(EX_CS0_N_MARK, FN_EX_CS0_N), + PINMUX_DATA(RD_N_MARK, FN_RD_N), + PINMUX_DATA(AUDIO_CLKA_MARK, FN_AUDIO_CLKA), + PINMUX_DATA(VI0_CLK_MARK, FN_VI0_CLK), + PINMUX_DATA(VI0_DATA0_VI0_B0_MARK, FN_VI0_DATA0_VI0_B0), + PINMUX_DATA(VI0_DATA1_VI0_B1_MARK, FN_VI0_DATA1_VI0_B1), + PINMUX_DATA(VI0_DATA2_VI0_B2_MARK, FN_VI0_DATA2_VI0_B2), + PINMUX_DATA(VI0_DATA4_VI0_B4_MARK, FN_VI0_DATA4_VI0_B4), + PINMUX_DATA(VI0_DATA5_VI0_B5_MARK, FN_VI0_DATA5_VI0_B5), + PINMUX_DATA(VI0_DATA6_VI0_B6_MARK, FN_VI0_DATA6_VI0_B6), + PINMUX_DATA(VI0_DATA7_VI0_B7_MARK, FN_VI0_DATA7_VI0_B7), + PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN), + PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC), + PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN), + PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC), + PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN), + + /* IPSR0 */ + PINMUX_IPSR_DATA(IP0_0, D0), + PINMUX_IPSR_DATA(IP0_1, D1), + PINMUX_IPSR_DATA(IP0_2, D2), + PINMUX_IPSR_DATA(IP0_3, D3), + PINMUX_IPSR_DATA(IP0_4, D4), + PINMUX_IPSR_DATA(IP0_5, D5), + PINMUX_IPSR_DATA(IP0_6, D6), + PINMUX_IPSR_DATA(IP0_7, D7), + PINMUX_IPSR_DATA(IP0_8, D8), + PINMUX_IPSR_DATA(IP0_9, D9), + PINMUX_IPSR_DATA(IP0_10, D10), + PINMUX_IPSR_DATA(IP0_11, D11), + PINMUX_IPSR_DATA(IP0_12, D12), + PINMUX_IPSR_DATA(IP0_13, D13), + PINMUX_IPSR_DATA(IP0_14, D14), + PINMUX_IPSR_DATA(IP0_15, D15), + PINMUX_IPSR_DATA(IP0_18_16, A0), + PINMUX_IPSR_MODSEL_DATA(IP0_18_16, ATAWR0_N_C, SEL_LBS_2), + PINMUX_IPSR_MODSEL_DATA(IP0_18_16, MSIOF0_SCK_B, SEL_SOF0_1), + PINMUX_IPSR_MODSEL_DATA(IP0_18_16, SCL0_C, SEL_IIC0_2), + PINMUX_IPSR_DATA(IP0_18_16, PWM2_B), + PINMUX_IPSR_DATA(IP0_20_19, A1), + PINMUX_IPSR_MODSEL_DATA(IP0_20_19, MSIOF0_SYNC_B, SEL_SOF0_1), + PINMUX_IPSR_DATA(IP0_22_21, A2), + PINMUX_IPSR_MODSEL_DATA(IP0_22_21, MSIOF0_SS1_B, SEL_SOF0_1), + PINMUX_IPSR_DATA(IP0_24_23, A3), + PINMUX_IPSR_MODSEL_DATA(IP0_24_23, MSIOF0_SS2_B, SEL_SOF0_1), + PINMUX_IPSR_DATA(IP0_26_25, A4), + PINMUX_IPSR_MODSEL_DATA(IP0_26_25, MSIOF0_TXD_B, SEL_SOF0_1), + PINMUX_IPSR_DATA(IP0_28_27, A5), + PINMUX_IPSR_MODSEL_DATA(IP0_28_27, MSIOF0_RXD_B, SEL_SOF0_1), + PINMUX_IPSR_DATA(IP0_30_29, A6), + PINMUX_IPSR_MODSEL_DATA(IP0_30_29, MSIOF1_SCK, SEL_SOF1_0), + + /* IPSR1 */ + PINMUX_IPSR_DATA(IP1_1_0, A7), + PINMUX_IPSR_MODSEL_DATA(IP1_1_0, MSIOF1_SYNC, SEL_SOF1_0), + PINMUX_IPSR_DATA(IP1_3_2, A8), + PINMUX_IPSR_MODSEL_DATA(IP1_3_2, MSIOF1_SS1, SEL_SOF1_0), + PINMUX_IPSR_MODSEL_DATA(IP1_3_2, SCL0, SEL_IIC0_0), + PINMUX_IPSR_DATA(IP1_5_4, A9), + PINMUX_IPSR_MODSEL_DATA(IP1_5_4, MSIOF1_SS2, SEL_SOF1_0), + PINMUX_IPSR_MODSEL_DATA(IP1_5_4, SDA0, SEL_IIC0_0), + PINMUX_IPSR_DATA(IP1_7_6, A10), + PINMUX_IPSR_MODSEL_DATA(IP1_7_6, MSIOF1_TXD, SEL_SOF1_0), + PINMUX_IPSR_MODSEL_DATA(IP1_7_6, MSIOF1_TXD_D, SEL_SOF1_3), + PINMUX_IPSR_DATA(IP1_10_8, A11), + PINMUX_IPSR_MODSEL_DATA(IP1_10_8, MSIOF1_RXD, SEL_SOF1_0), + PINMUX_IPSR_MODSEL_DATA(IP1_10_8, SCL3_D, SEL_IIC3_3), + PINMUX_IPSR_MODSEL_DATA(IP1_10_8, MSIOF1_RXD_D, SEL_SOF1_3), + PINMUX_IPSR_DATA(IP1_13_11, A12), + PINMUX_IPSR_MODSEL_DATA(IP1_13_11, FMCLK, SEL_FM_0), + PINMUX_IPSR_MODSEL_DATA(IP1_13_11, SDA3_D, SEL_IIC3_3), + PINMUX_IPSR_MODSEL_DATA(IP1_13_11, MSIOF1_SCK_D, SEL_SOF1_3), + PINMUX_IPSR_DATA(IP1_16_14, A13), + PINMUX_IPSR_MODSEL_DATA(IP1_16_14, ATAG0_N_C, SEL_LBS_2), + PINMUX_IPSR_MODSEL_DATA(IP1_16_14, BPFCLK, SEL_FM_0), + PINMUX_IPSR_MODSEL_DATA(IP1_16_14, MSIOF1_SS1_D, SEL_SOF1_3), + PINMUX_IPSR_DATA(IP1_19_17, A14), + PINMUX_IPSR_MODSEL_DATA(IP1_19_17, ATADIR0_N_C, SEL_LBS_2), + PINMUX_IPSR_MODSEL_DATA(IP1_19_17, FMIN, SEL_FM_0), + PINMUX_IPSR_MODSEL_DATA(IP1_19_17, FMIN_C, SEL_FM_2), + PINMUX_IPSR_MODSEL_DATA(IP1_19_17, MSIOF1_SYNC_D, SEL_SOF1_3), + PINMUX_IPSR_DATA(IP1_22_20, A15), + PINMUX_IPSR_MODSEL_DATA(IP1_22_20, BPFCLK_C, SEL_FM_2), + PINMUX_IPSR_DATA(IP1_25_23, A16), + PINMUX_IPSR_MODSEL_DATA(IP1_25_23, DREQ2_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FMCLK_C, SEL_FM_2), + PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SCIFA1_SCK_B, SEL_SCIFA1_1), + PINMUX_IPSR_DATA(IP1_28_26, A17), + PINMUX_IPSR_MODSEL_DATA(IP1_28_26, DACK2_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SDA0_C, SEL_IIC0_2), + PINMUX_IPSR_DATA(IP1_31_29, A18), + PINMUX_IPSR_MODSEL_DATA(IP1_31_29, DREQ1, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SCIFA1_RXD_C, SEL_SCIFA1_2), + PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SCIFB1_RXD_C, SEL_SCIFB1_2), + + /* IPSR2 */ + PINMUX_IPSR_DATA(IP2_2_0, A19), + PINMUX_IPSR_DATA(IP2_2_0, DACK1), + PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SCIFA1_TXD_C, SEL_SCIFA1_2), + PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SCIFB1_TXD_C, SEL_SCIFB1_2), + PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SCIFB1_SCK_B, SEL_SCIFB1_0), + PINMUX_IPSR_DATA(IP2_2_0, A20), + PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SPCLK, SEL_QSP_0), + PINMUX_IPSR_DATA(IP2_6_5, A21), + PINMUX_IPSR_MODSEL_DATA(IP2_6_5, ATAWR0_N_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP2_6_5, MOSI_IO0, SEL_QSP_0), + PINMUX_IPSR_DATA(IP2_9_7, A22), + PINMUX_IPSR_MODSEL_DATA(IP2_9_7, MISO_IO1, SEL_QSP_0), + PINMUX_IPSR_MODSEL_DATA(IP2_9_7, FMCLK_B, SEL_FM_1), + PINMUX_IPSR_MODSEL_DATA(IP2_9_7, TX0, SEL_SCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP2_9_7, SCIFA0_TXD, SEL_SCFA_0), + PINMUX_IPSR_DATA(IP2_12_10, A23), + PINMUX_IPSR_MODSEL_DATA(IP2_12_10, IO2, SEL_QSP_0), + PINMUX_IPSR_MODSEL_DATA(IP2_12_10, BPFCLK_B, SEL_FM_1), + PINMUX_IPSR_MODSEL_DATA(IP2_12_10, RX0, SEL_SCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP2_12_10, SCIFA0_RXD, SEL_SCFA_0), + PINMUX_IPSR_DATA(IP2_15_13, A24), + PINMUX_IPSR_MODSEL_DATA(IP2_15_13, DREQ2, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP2_15_13, IO3, SEL_QSP_0), + PINMUX_IPSR_MODSEL_DATA(IP2_15_13, TX1, SEL_SCIF1_0), + PINMUX_IPSR_MODSEL_DATA(IP2_15_13, SCIFA1_TXD, SEL_SCIFA1_0), + PINMUX_IPSR_DATA(IP2_18_16, A25), + PINMUX_IPSR_MODSEL_DATA(IP2_18_16, DACK2, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP2_18_16, SSL, SEL_QSP_0), + PINMUX_IPSR_MODSEL_DATA(IP2_18_16, DREQ1_C, SEL_LBS_2), + PINMUX_IPSR_MODSEL_DATA(IP2_18_16, RX1, SEL_SCIF1_0), + PINMUX_IPSR_MODSEL_DATA(IP2_18_16, SCIFA1_RXD, SEL_SCIFA1_0), + PINMUX_IPSR_DATA(IP2_20_19, CS0_N), + PINMUX_IPSR_MODSEL_DATA(IP2_20_19, ATAG0_N_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP2_20_19, SCL1, SEL_IIC1_0), + PINMUX_IPSR_DATA(IP2_22_21, CS1_N_A26), + PINMUX_IPSR_MODSEL_DATA(IP2_22_21, ATADIR0_N_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP2_22_21, SDA1, SEL_IIC1_0), + PINMUX_IPSR_DATA(IP2_24_23, EX_CS1_N), + PINMUX_IPSR_MODSEL_DATA(IP2_24_23, MSIOF2_SCK, SEL_SOF2_0), + PINMUX_IPSR_DATA(IP2_26_25, EX_CS2_N), + PINMUX_IPSR_MODSEL_DATA(IP2_26_25, ATAWR0_N, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP2_26_25, MSIOF2_SYNC, SEL_SOF2_0), + PINMUX_IPSR_DATA(IP2_29_27, EX_CS3_N), + PINMUX_IPSR_MODSEL_DATA(IP2_29_27, ATADIR0_N, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP2_29_27, MSIOF2_TXD, SEL_SOF2_0), + PINMUX_IPSR_MODSEL_DATA(IP2_29_27, ATAG0_N, SEL_LBS_0), + PINMUX_IPSR_DATA(IP2_29_27, EX_WAIT1), + + /* IPSR3 */ + PINMUX_IPSR_DATA(IP3_2_0, EX_CS4_N), + PINMUX_IPSR_MODSEL_DATA(IP3_2_0, ATARD0_N, SEL_LBS_0), + PINMUX_IPSR_MODSEL_DATA(IP3_2_0, MSIOF2_RXD, SEL_SOF2_0), + PINMUX_IPSR_DATA(IP3_2_0, EX_WAIT2), + PINMUX_IPSR_DATA(IP3_5_3, EX_CS5_N), + PINMUX_IPSR_DATA(IP3_5_3, ATACS00_N), + PINMUX_IPSR_MODSEL_DATA(IP3_5_3, MSIOF2_SS1, SEL_SOF2_0), + PINMUX_IPSR_MODSEL_DATA(IP3_5_3, HRX1_B, SEL_HSCIF1_1), + PINMUX_IPSR_MODSEL_DATA(IP3_5_3, SCIFB1_RXD_B, SEL_SCIFB1_1), + PINMUX_IPSR_DATA(IP3_5_3, PWM1), + PINMUX_IPSR_DATA(IP3_5_3, TPU_TO1), + PINMUX_IPSR_DATA(IP3_8_6, BS_N), + PINMUX_IPSR_DATA(IP3_8_6, ATACS10_N), + PINMUX_IPSR_MODSEL_DATA(IP3_8_6, MSIOF2_SS2, SEL_SOF2_0), + PINMUX_IPSR_MODSEL_DATA(IP3_8_6, HTX1_B, SEL_HSCIF1_1), + PINMUX_IPSR_MODSEL_DATA(IP3_8_6, SCIFB1_TXD_B, SEL_SCIFB1_1), + PINMUX_IPSR_DATA(IP3_8_6, PWM2), + PINMUX_IPSR_DATA(IP3_8_6, TPU_TO2), + PINMUX_IPSR_DATA(IP3_11_9, RD_WR_N), + PINMUX_IPSR_MODSEL_DATA(IP3_11_9, HRX2_B, SEL_HSCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP3_11_9, FMIN_B, SEL_FM_1), + PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SCIFB0_RXD_B, SEL_SCIFB_1), + PINMUX_IPSR_MODSEL_DATA(IP3_11_9, DREQ1_D, SEL_LBS_1), + PINMUX_IPSR_DATA(IP3_13_12, WE0_N), + PINMUX_IPSR_MODSEL_DATA(IP3_13_12, HCTS2_N_B, SEL_HSCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP3_13_12, SCIFB0_TXD_B, SEL_SCIFB_1), + PINMUX_IPSR_DATA(IP3_15_14, WE1_N), + PINMUX_IPSR_MODSEL_DATA(IP3_15_14, ATARD0_N_B, SEL_LBS_1), + PINMUX_IPSR_MODSEL_DATA(IP3_15_14, HTX2_B, SEL_HSCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP3_15_14, SCIFB0_RTS_N_B, SEL_SCIFB_1), + PINMUX_IPSR_DATA(IP3_17_16, EX_WAIT0), + PINMUX_IPSR_MODSEL_DATA(IP3_17_16, HRTS2_N_B, SEL_HSCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP3_17_16, SCIFB0_CTS_N_B, SEL_SCIFB_1), + PINMUX_IPSR_DATA(IP3_19_18, DREQ0), + PINMUX_IPSR_DATA(IP3_19_18, PWM3), + PINMUX_IPSR_DATA(IP3_19_18, TPU_TO3), + PINMUX_IPSR_DATA(IP3_21_20, DACK0), + PINMUX_IPSR_DATA(IP3_21_20, DRACK0), + PINMUX_IPSR_MODSEL_DATA(IP3_21_20, REMOCON, SEL_RCN_0), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, SPEEDIN, SEL_RSP_0), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, HSCK0_C, SEL_HSCIF0_2), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, HSCK2_C, SEL_HSCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, SCIFB0_SCK_B, SEL_SCIFB_1), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, SCIFB2_SCK_B, SEL_SCIFB2_1), + PINMUX_IPSR_MODSEL_DATA(IP3_24_22, DREQ2_C, SEL_LBS_2), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, HTX2_C, SEL_HSCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP3_27_25, SSI_SCK0129, SEL_SSI0_0), + PINMUX_IPSR_MODSEL_DATA(IP3_27_25, HRX0_C, SEL_HSCIF0_2), + PINMUX_IPSR_MODSEL_DATA(IP3_27_25, HRX2_C, SEL_HSCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP3_27_25, SCIFB0_RXD_C, SEL_SCIFB_2), + PINMUX_IPSR_MODSEL_DATA(IP3_27_25, SCIFB2_RXD_C, SEL_SCIFB2_2), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, SSI_WS0129, SEL_SSI0_0), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, HTX0_C, SEL_HSCIF0_2), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, HTX2_C, SEL_HSCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, SCIFB0_TXD_C, SEL_SCIFB_2), + PINMUX_IPSR_MODSEL_DATA(IP3_30_28, SCIFB2_TXD_C, SEL_SCIFB2_2), + + /* IPSR4 */ + PINMUX_IPSR_MODSEL_DATA(IP4_1_0, SSI_SDATA0, SEL_SSI0_0), + PINMUX_IPSR_MODSEL_DATA(IP4_1_0, SCL0_B, SEL_IIC0_1), + PINMUX_IPSR_MODSEL_DATA(IP4_1_0, SCL7_B, SEL_IIC7_1), + PINMUX_IPSR_MODSEL_DATA(IP4_1_0, MSIOF2_SCK_C, SEL_SOF2_2), + PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SSI_SCK1, SEL_SSI1_0), + PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SDA0_B, SEL_IIC0_1), + PINMUX_IPSR_MODSEL_DATA(IP4_4_2, SDA7_B, SEL_IIC7_1), + PINMUX_IPSR_MODSEL_DATA(IP4_4_2, MSIOF2_SYNC_C, SEL_SOF2_2), + PINMUX_IPSR_MODSEL_DATA(IP4_4_2, GLO_I0_D, SEL_GPS_3), + PINMUX_IPSR_MODSEL_DATA(IP4_7_5, SSI_WS1, SEL_SSI1_0), + PINMUX_IPSR_MODSEL_DATA(IP4_7_5, SCL1_B, SEL_IIC1_1), + PINMUX_IPSR_MODSEL_DATA(IP4_7_5, SCL8_B, SEL_IIC8_1), + PINMUX_IPSR_MODSEL_DATA(IP4_7_5, MSIOF2_TXD_C, SEL_SOF2_2), + PINMUX_IPSR_MODSEL_DATA(IP4_7_5, GLO_I1_D, SEL_GPS_3), + PINMUX_IPSR_MODSEL_DATA(IP4_9_8, SSI_SDATA1, SEL_SSI1_0), + PINMUX_IPSR_MODSEL_DATA(IP4_9_8, SDA1_B, SEL_IIC1_1), + PINMUX_IPSR_MODSEL_DATA(IP4_9_8, SDA8_B, SEL_IIC8_1), + PINMUX_IPSR_MODSEL_DATA(IP4_9_8, MSIOF2_RXD_C, SEL_SOF2_2), + PINMUX_IPSR_DATA(IP4_12_10, SSI_SCK2), + PINMUX_IPSR_MODSEL_DATA(IP4_12_10, SCL2, SEL_IIC2_0), + PINMUX_IPSR_MODSEL_DATA(IP4_12_10, GPS_CLK_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP4_12_10, GLO_Q0_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP4_15_13, SSI_WS2), + PINMUX_IPSR_MODSEL_DATA(IP4_15_13, SDA2, SEL_IIC2_0), + PINMUX_IPSR_MODSEL_DATA(IP4_15_13, GPS_SIGN_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP4_15_13, RX2_E, SEL_SCIF2_4), + PINMUX_IPSR_MODSEL_DATA(IP4_15_13, GLO_Q1_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP4_18_16, SSI_SDATA2), + PINMUX_IPSR_MODSEL_DATA(IP4_18_16, GPS_MAG_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP4_18_16, TX2_E, SEL_SCIF2_4), + PINMUX_IPSR_DATA(IP4_19, SSI_SCK34), + PINMUX_IPSR_DATA(IP4_20, SSI_WS34), + PINMUX_IPSR_DATA(IP4_21, SSI_SDATA3), + PINMUX_IPSR_DATA(IP4_23_22, SSI_SCK4), + PINMUX_IPSR_MODSEL_DATA(IP4_23_22, GLO_SS_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP4_25_24, SSI_WS4), + PINMUX_IPSR_MODSEL_DATA(IP4_25_24, GLO_RFON_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP4_27_26, SSI_SDATA4), + PINMUX_IPSR_MODSEL_DATA(IP4_27_26, MSIOF2_SCK_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP4_30_28, SSI_SCK5), + PINMUX_IPSR_MODSEL_DATA(IP4_30_28, MSIOF1_SCK_C, SEL_SOF1_2), + PINMUX_IPSR_MODSEL_DATA(IP4_30_28, TS_SDATA0, SEL_TSIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP4_30_28, GLO_I0, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP4_30_28, MSIOF2_SYNC_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP4_30_28, VI1_R2_B), + + /* IPSR5 */ + PINMUX_IPSR_DATA(IP5_2_0, SSI_WS5), + PINMUX_IPSR_MODSEL_DATA(IP5_2_0, MSIOF1_SYNC_C, SEL_SOF1_2), + PINMUX_IPSR_MODSEL_DATA(IP5_2_0, TS_SCK0, SEL_TSIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP5_2_0, GLO_I1, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_2_0, MSIOF2_TXD_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP5_2_0, VI1_R3_B), + PINMUX_IPSR_DATA(IP5_5_3, SSI_SDATA5), + PINMUX_IPSR_MODSEL_DATA(IP5_5_3, MSIOF1_TXD_C, SEL_SOF1_2), + PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TS_SDEN0, SEL_TSIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP5_5_3, GLO_Q0, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_5_3, MSIOF2_SS1_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP5_5_3, VI1_R4_B), + PINMUX_IPSR_DATA(IP5_8_6, SSI_SCK6), + PINMUX_IPSR_MODSEL_DATA(IP5_8_6, MSIOF1_RXD_C, SEL_SOF1_2), + PINMUX_IPSR_MODSEL_DATA(IP5_8_6, TS_SPSYNC0, SEL_TSIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP5_8_6, GLO_Q1, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_8_6, MSIOF2_RXD_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP5_8_6, VI1_R5_B), + PINMUX_IPSR_DATA(IP5_11_9, SSI_WS6), + PINMUX_IPSR_MODSEL_DATA(IP5_11_9, GLO_SCLK, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_11_9, MSIOF2_SS2_D, SEL_SOF2_3), + PINMUX_IPSR_DATA(IP5_11_9, VI1_R6_B), + PINMUX_IPSR_DATA(IP5_14_12, SSI_SDATA6), + PINMUX_IPSR_MODSEL_DATA(IP5_14_12, STP_IVCXO27_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP5_14_12, GLO_SDATA, SEL_GPS_0), + PINMUX_IPSR_DATA(IP5_14_12, VI1_R7_B), + PINMUX_IPSR_MODSEL_DATA(IP5_16_15, SSI_SCK78, SEL_SSI7_0), + PINMUX_IPSR_MODSEL_DATA(IP5_16_15, STP_ISCLK_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP5_16_15, GLO_SS, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_19_17, SSI_WS78, SEL_SSI7_0), + PINMUX_IPSR_MODSEL_DATA(IP5_19_17, TX0_D, SEL_SCIF0_3), + PINMUX_IPSR_MODSEL_DATA(IP5_19_17, STP_ISD_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP5_19_17, GLO_RFON, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP5_21_20, SSI_SDATA7, SEL_SSI7_0), + PINMUX_IPSR_MODSEL_DATA(IP5_21_20, RX0_D, SEL_SCIF0_3), + PINMUX_IPSR_MODSEL_DATA(IP5_21_20, STP_ISEN_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP5_23_22, SSI_SDATA8, SEL_SSI8_0), + PINMUX_IPSR_MODSEL_DATA(IP5_23_22, TX1_D, SEL_SCIF1_3), + PINMUX_IPSR_MODSEL_DATA(IP5_23_22, STP_ISSYNC_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP5_25_24, SSI_SCK9, SEL_SSI9_0), + PINMUX_IPSR_MODSEL_DATA(IP5_25_24, RX1_D, SEL_SCIF1_3), + PINMUX_IPSR_MODSEL_DATA(IP5_25_24, GLO_SCLK_D, SEL_GPS_3), + PINMUX_IPSR_MODSEL_DATA(IP5_28_26, SSI_WS9, SEL_SSI9_0), + PINMUX_IPSR_MODSEL_DATA(IP5_28_26, TX3_D, SEL_SCIF3_3), + PINMUX_IPSR_MODSEL_DATA(IP5_28_26, CAN0_TX_D, SEL_CAN0_3), + PINMUX_IPSR_MODSEL_DATA(IP5_28_26, GLO_SDATA_D, SEL_GPS_3), + PINMUX_IPSR_MODSEL_DATA(IP5_31_29, SSI_SDATA9, SEL_SSI9_0), + PINMUX_IPSR_MODSEL_DATA(IP5_31_29, RX3_D, SEL_SCIF3_3), + PINMUX_IPSR_MODSEL_DATA(IP5_31_29, CAN0_RX_D, SEL_CAN0_3), + + /* IPSR6 */ + PINMUX_IPSR_MODSEL_DATA(IP6_2_0, AUDIO_CLKB, SEL_ADG_0), + PINMUX_IPSR_MODSEL_DATA(IP6_2_0, STP_OPWM_0_B, SEL_SSP_1), + PINMUX_IPSR_MODSEL_DATA(IP6_2_0, MSIOF1_SCK_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK, SEL_SCIF_0), + PINMUX_IPSR_MODSEL_DATA(IP6_2_0, BPFCLK_E, SEL_FM_4), + PINMUX_IPSR_DATA(IP6_5_3, AUDIO_CLKC), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCIFB0_SCK_C, SEL_SCIFB_2), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, MSIOF1_SYNC_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, RX2, SEL_SCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCIFA2_RXD, SEL_SCIFA2_0), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, FMIN_E, SEL_FM_4), + PINMUX_IPSR_DATA(IP6_7_6, AUDIO_CLKOUT), + PINMUX_IPSR_MODSEL_DATA(IP6_7_6, MSIOF1_SS1_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TX2, SEL_SCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP6_7_6, SCIFA2_TXD, SEL_SCIFA2_0), + PINMUX_IPSR_DATA(IP6_9_8, IRQ0), + PINMUX_IPSR_MODSEL_DATA(IP6_9_8, SCIFB1_RXD_D, SEL_SCIFB1_3), + PINMUX_IPSR_DATA(IP6_9_8, INTC_IRQ0_N), + PINMUX_IPSR_DATA(IP6_11_10, IRQ1), + PINMUX_IPSR_MODSEL_DATA(IP6_11_10, SCIFB1_SCK_C, SEL_SCIFB1_2), + PINMUX_IPSR_DATA(IP6_11_10, INTC_IRQ1_N), + PINMUX_IPSR_DATA(IP6_13_12, IRQ2), + PINMUX_IPSR_MODSEL_DATA(IP6_13_12, SCIFB1_TXD_D, SEL_SCIFB1_3), + PINMUX_IPSR_DATA(IP6_13_12, INTC_IRQ2_N), + PINMUX_IPSR_DATA(IP6_15_14, IRQ3), + PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCL4_C, SEL_IIC4_2), + PINMUX_IPSR_MODSEL_DATA(IP6_15_14, MSIOF2_TXD_E, SEL_SOF2_4), + PINMUX_IPSR_DATA(IP6_15_14, INTC_IRQ4_N), + PINMUX_IPSR_DATA(IP6_18_16, IRQ4), + PINMUX_IPSR_MODSEL_DATA(IP6_18_16, HRX1_C, SEL_HSCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP6_18_16, SDA4_C, SEL_IIC4_2), + PINMUX_IPSR_MODSEL_DATA(IP6_18_16, MSIOF2_RXD_E, SEL_SOF2_4), + PINMUX_IPSR_DATA(IP6_18_16, INTC_IRQ4_N), + PINMUX_IPSR_DATA(IP6_20_19, IRQ5), + PINMUX_IPSR_MODSEL_DATA(IP6_20_19, HTX1_C, SEL_HSCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP6_20_19, SCL1_E, SEL_IIC1_4), + PINMUX_IPSR_MODSEL_DATA(IP6_20_19, MSIOF2_SCK_E, SEL_SOF2_4), + PINMUX_IPSR_DATA(IP6_23_21, IRQ6), + PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HSCK1_C, SEL_HSCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP6_23_21, MSIOF1_SS2_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_23_21, SDA1_E, SEL_IIC1_4), + PINMUX_IPSR_MODSEL_DATA(IP6_23_21, MSIOF2_SYNC_E, SEL_SOF2_4), + PINMUX_IPSR_DATA(IP6_26_24, IRQ7), + PINMUX_IPSR_MODSEL_DATA(IP6_26_24, HCTS1_N_C, SEL_HSCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP6_26_24, MSIOF1_TXD_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_26_24, GPS_CLK_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP6_26_24, GPS_CLK_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP6_29_27, IRQ8), + PINMUX_IPSR_MODSEL_DATA(IP6_29_27, HRTS1_N_C, SEL_HSCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP6_29_27, MSIOF1_RXD_B, SEL_SOF1_1), + PINMUX_IPSR_MODSEL_DATA(IP6_29_27, GPS_SIGN_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP6_29_27, GPS_SIGN_D, SEL_GPS_3), + + /* IPSR7 */ + PINMUX_IPSR_DATA(IP7_2_0, IRQ9), + PINMUX_IPSR_MODSEL_DATA(IP7_2_0, DU1_DOTCLKIN_B, SEL_DIS_1), + PINMUX_IPSR_MODSEL_DATA(IP7_2_0, CAN_CLK_D, SEL_CANCLK_3), + PINMUX_IPSR_MODSEL_DATA(IP7_2_0, GPS_MAG_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP7_2_0, SCIF_CLK_B, SEL_SCIF_1), + PINMUX_IPSR_MODSEL_DATA(IP7_2_0, GPS_MAG_D, SEL_GPS_3), + PINMUX_IPSR_DATA(IP7_5_3, DU1_DR0), + PINMUX_IPSR_DATA(IP7_5_3, LCDOUT0), + PINMUX_IPSR_MODSEL_DATA(IP7_5_3, VI1_DATA0_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TX0_B, SEL_SCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCIFA0_TXD_B, SEL_SCFA_1), + PINMUX_IPSR_MODSEL_DATA(IP7_5_3, MSIOF2_SCK_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP7_8_6, DU1_DR1), + PINMUX_IPSR_DATA(IP7_8_6, LCDOUT1), + PINMUX_IPSR_MODSEL_DATA(IP7_8_6, VI1_DATA1_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX0_B, SEL_SCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP7_8_6, SCIFA0_RXD_B, SEL_SCFA_1), + PINMUX_IPSR_MODSEL_DATA(IP7_8_6, MSIOF2_SYNC_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP7_10_9, DU1_DR2), + PINMUX_IPSR_DATA(IP7_10_9, LCDOUT2), + PINMUX_IPSR_MODSEL_DATA(IP7_10_9, SSI_SCK0129_B, SEL_SSI0_1), + PINMUX_IPSR_DATA(IP7_12_11, DU1_DR3), + PINMUX_IPSR_DATA(IP7_12_11, LCDOUT3), + PINMUX_IPSR_MODSEL_DATA(IP7_12_11, SSI_WS0129_B, SEL_SSI0_1), + PINMUX_IPSR_DATA(IP7_14_13, DU1_DR4), + PINMUX_IPSR_DATA(IP7_14_13, LCDOUT4), + PINMUX_IPSR_MODSEL_DATA(IP7_14_13, SSI_SDATA0_B, SEL_SSI0_1), + PINMUX_IPSR_DATA(IP7_16_15, DU1_DR5), + PINMUX_IPSR_DATA(IP7_16_15, LCDOUT5), + PINMUX_IPSR_MODSEL_DATA(IP7_16_15, SSI_SCK1_B, SEL_SSI1_1), + PINMUX_IPSR_DATA(IP7_18_17, DU1_DR6), + PINMUX_IPSR_DATA(IP7_18_17, LCDOUT6), + PINMUX_IPSR_MODSEL_DATA(IP7_18_17, SSI_WS1_B, SEL_SSI1_1), + PINMUX_IPSR_DATA(IP7_20_19, DU1_DR7), + PINMUX_IPSR_DATA(IP7_20_19, LCDOUT7), + PINMUX_IPSR_MODSEL_DATA(IP7_20_19, SSI_SDATA1_B, SEL_SSI1_1), + PINMUX_IPSR_DATA(IP7_23_21, DU1_DG0), + PINMUX_IPSR_DATA(IP7_23_21, LCDOUT8), + PINMUX_IPSR_MODSEL_DATA(IP7_23_21, VI1_DATA2_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX1_B, SEL_SCIF1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_23_21, SCIFA1_TXD_B, SEL_SCIFA1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_23_21, MSIOF2_SS1_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP7_26_24, DU1_DG1), + PINMUX_IPSR_DATA(IP7_26_24, LCDOUT9), + PINMUX_IPSR_MODSEL_DATA(IP7_26_24, VI1_DATA3_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX1_B, SEL_SCIF1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_26_24, SCIFA1_RXD_B, SEL_SCIFA1_1), + PINMUX_IPSR_MODSEL_DATA(IP7_26_24, MSIOF2_SS2_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP7_29_27, DU1_DG2), + PINMUX_IPSR_DATA(IP7_29_27, LCDOUT10), + PINMUX_IPSR_MODSEL_DATA(IP7_29_27, VI1_DATA4_B, SEL_VI1_1), + PINMUX_IPSR_DATA(IP7_29_27, SCIF1_SCK_B), + PINMUX_IPSR_MODSEL_DATA(IP7_29_27, SCIFA1_SCK, SEL_SCIFA1_0), + PINMUX_IPSR_MODSEL_DATA(IP7_29_27, SSI_SCK78_B, SEL_SSI7_1), + + /* IPSR8 */ + PINMUX_IPSR_DATA(IP8_2_0, DU1_DG3), + PINMUX_IPSR_DATA(IP8_2_0, LCDOUT11), + PINMUX_IPSR_MODSEL_DATA(IP8_2_0, VI1_DATA5_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_2_0, SSI_WS78_B, SEL_SSI7_1), + PINMUX_IPSR_DATA(IP8_5_3, DU1_DG4), + PINMUX_IPSR_DATA(IP8_5_3, LCDOUT12), + PINMUX_IPSR_MODSEL_DATA(IP8_5_3, VI1_DATA6_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_5_3, HRX0_B, SEL_HSCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP8_5_3, SCIFB2_RXD_B, SEL_SCIFB2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_5_3, SSI_SDATA7_B, SEL_SSI7_1), + PINMUX_IPSR_DATA(IP8_8_6, DU1_DG5), + PINMUX_IPSR_DATA(IP8_8_6, LCDOUT13), + PINMUX_IPSR_MODSEL_DATA(IP8_8_6, VI1_DATA7_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_8_6, HCTS0_N_B, SEL_HSCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP8_8_6, SCIFB2_TXD_B, SEL_SCIFB2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_8_6, SSI_SDATA8_B, SEL_SSI8_1), + PINMUX_IPSR_DATA(IP8_11_9, DU1_DG6), + PINMUX_IPSR_DATA(IP8_11_9, LCDOUT14), + PINMUX_IPSR_MODSEL_DATA(IP8_11_9, HRTS0_N_B, SEL_HSCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP8_11_9, SCIFB2_CTS_N_B, SEL_SCIFB2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_11_9, SSI_SCK9_B, SEL_SSI9_1), + PINMUX_IPSR_DATA(IP8_14_12, DU1_DG7), + PINMUX_IPSR_DATA(IP8_14_12, LCDOUT15), + PINMUX_IPSR_MODSEL_DATA(IP8_14_12, HTX0_B, SEL_HSCIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP8_14_12, SCIFB2_RTS_N_B, SEL_SCIFB2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_14_12, SSI_WS9_B, SEL_SSI9_1), + PINMUX_IPSR_DATA(IP8_17_15, DU1_DB0), + PINMUX_IPSR_DATA(IP8_17_15, LCDOUT16), + PINMUX_IPSR_MODSEL_DATA(IP8_17_15, VI1_CLK_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_17_15, TX2_B, SEL_SCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_17_15, SCIFA2_TXD_B, SEL_SCIFA2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_17_15, MSIOF2_TXD_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP8_20_18, DU1_DB1), + PINMUX_IPSR_DATA(IP8_20_18, LCDOUT17), + PINMUX_IPSR_MODSEL_DATA(IP8_20_18, VI1_HSYNC_N_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_20_18, RX2_B, SEL_SCIF2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_20_18, SCIFA2_RXD_B, SEL_SCIFA2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_20_18, MSIOF2_RXD_B, SEL_SOF2_1), + PINMUX_IPSR_DATA(IP8_23_21, DU1_DB2), + PINMUX_IPSR_DATA(IP8_23_21, LCDOUT18), + PINMUX_IPSR_MODSEL_DATA(IP8_23_21, VI1_VSYNC_N_B, SEL_VI1_1), + PINMUX_IPSR_DATA(IP8_23_21, SCIF2_SCK_B), + PINMUX_IPSR_MODSEL_DATA(IP8_23_21, SCIFA2_SCK, SEL_SCIFA2_1), + PINMUX_IPSR_MODSEL_DATA(IP8_23_21, SSI_SDATA9_B, SEL_SSI9_1), + PINMUX_IPSR_DATA(IP8_25_24, DU1_DB3), + PINMUX_IPSR_DATA(IP8_25_24, LCDOUT19), + PINMUX_IPSR_MODSEL_DATA(IP8_25_24, VI1_CLKENB_B, SEL_VI1_1), + PINMUX_IPSR_DATA(IP8_27_26, DU1_DB4), + PINMUX_IPSR_DATA(IP8_27_26, LCDOUT20), + PINMUX_IPSR_MODSEL_DATA(IP8_27_26, VI1_FIELD_B, SEL_VI1_1), + PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CAN1_RX, SEL_CAN1_0), + PINMUX_IPSR_DATA(IP8_30_28, DU1_DB5), + PINMUX_IPSR_DATA(IP8_30_28, LCDOUT21), + PINMUX_IPSR_MODSEL_DATA(IP8_30_28, TX3, SEL_SCIF3_0), + PINMUX_IPSR_MODSEL_DATA(IP8_30_28, SCIFA3_TXD, SEL_SCIFA3_0), + PINMUX_IPSR_MODSEL_DATA(IP8_30_28, CAN1_TX, SEL_CAN1_0), + + /* IPSR9 */ + PINMUX_IPSR_DATA(IP9_2_0, DU1_DB6), + PINMUX_IPSR_DATA(IP9_2_0, LCDOUT22), + PINMUX_IPSR_MODSEL_DATA(IP9_2_0, SCL3_C, SEL_IIC3_2), + PINMUX_IPSR_MODSEL_DATA(IP9_2_0, RX3, SEL_SCIF3_0), + PINMUX_IPSR_MODSEL_DATA(IP9_2_0, SCIFA3_RXD, SEL_SCIFA3_0), + PINMUX_IPSR_DATA(IP9_5_3, DU1_DB7), + PINMUX_IPSR_DATA(IP9_5_3, LCDOUT23), + PINMUX_IPSR_MODSEL_DATA(IP9_5_3, SDA3_C, SEL_IIC3_2), + PINMUX_IPSR_MODSEL_DATA(IP9_5_3, SCIF3_SCK, SEL_SCIF3_0), + PINMUX_IPSR_MODSEL_DATA(IP9_5_3, SCIFA3_SCK, SEL_SCIFA3_0), + PINMUX_IPSR_MODSEL_DATA(IP9_6, DU1_DOTCLKIN, SEL_DIS_0), + PINMUX_IPSR_DATA(IP9_6, QSTVA_QVS), + PINMUX_IPSR_DATA(IP9_7, DU1_DOTCLKOUT0), + PINMUX_IPSR_DATA(IP9_7, QCLK), + PINMUX_IPSR_DATA(IP9_10_8, DU1_DOTCLKOUT1), + PINMUX_IPSR_DATA(IP9_10_8, QSTVB_QVE), + PINMUX_IPSR_MODSEL_DATA(IP9_10_8, CAN0_TX, SEL_CAN0_0), + PINMUX_IPSR_MODSEL_DATA(IP9_10_8, TX3_B, SEL_SCIF3_1), + PINMUX_IPSR_MODSEL_DATA(IP9_10_8, SCL2_B, SEL_IIC2_1), + PINMUX_IPSR_DATA(IP9_10_8, PWM4), + PINMUX_IPSR_DATA(IP9_11, DU1_EXHSYNC_DU1_HSYNC), + PINMUX_IPSR_DATA(IP9_11, QSTH_QHS), + PINMUX_IPSR_DATA(IP9_12, DU1_EXVSYNC_DU1_VSYNC), + PINMUX_IPSR_DATA(IP9_12, QSTB_QHE), + PINMUX_IPSR_DATA(IP9_15_13, DU1_EXODDF_DU1_ODDF_DISP_CDE), + PINMUX_IPSR_DATA(IP9_15_13, QCPV_QDE), + PINMUX_IPSR_MODSEL_DATA(IP9_15_13, CAN0_RX, SEL_CAN0_0), + PINMUX_IPSR_MODSEL_DATA(IP9_15_13, RX3_B, SEL_SCIF3_1), + PINMUX_IPSR_MODSEL_DATA(IP9_15_13, SDA2_B, SEL_IIC2_1), + PINMUX_IPSR_DATA(IP9_16, DU1_DISP), + PINMUX_IPSR_DATA(IP9_16, QPOLA), + PINMUX_IPSR_DATA(IP9_18_17, DU1_CDE), + PINMUX_IPSR_DATA(IP9_18_17, QPOLB), + PINMUX_IPSR_DATA(IP9_18_17, PWM4_B), + PINMUX_IPSR_DATA(IP9_20_19, VI0_CLKENB), + PINMUX_IPSR_MODSEL_DATA(IP9_20_19, TX4, SEL_SCIF4_0), + PINMUX_IPSR_MODSEL_DATA(IP9_20_19, SCIFA4_TXD, SEL_SCIFA4_0), + PINMUX_IPSR_MODSEL_DATA(IP9_20_19, TS_SDATA0_D, SEL_TSIF0_3), + PINMUX_IPSR_DATA(IP9_22_21, VI0_FIELD), + PINMUX_IPSR_MODSEL_DATA(IP9_22_21, RX4, SEL_SCIF4_0), + PINMUX_IPSR_MODSEL_DATA(IP9_22_21, SCIFA4_RXD, SEL_SCIFA4_0), + PINMUX_IPSR_MODSEL_DATA(IP9_22_21, TS_SCK0_D, SEL_TSIF0_3), + PINMUX_IPSR_DATA(IP9_24_23, VI0_HSYNC_N), + PINMUX_IPSR_MODSEL_DATA(IP9_24_23, TX5, SEL_SCIF5_0), + PINMUX_IPSR_MODSEL_DATA(IP9_24_23, SCIFA5_TXD, SEL_SCIFA5_0), + PINMUX_IPSR_MODSEL_DATA(IP9_24_23, TS_SDEN0_D, SEL_TSIF0_3), + PINMUX_IPSR_DATA(IP9_26_25, VI0_VSYNC_N), + PINMUX_IPSR_MODSEL_DATA(IP9_26_25, RX5, SEL_SCIF5_0), + PINMUX_IPSR_MODSEL_DATA(IP9_26_25, SCIFA5_RXD, SEL_SCIFA5_0), + PINMUX_IPSR_MODSEL_DATA(IP9_26_25, TS_SPSYNC0_D, SEL_TSIF0_3), + PINMUX_IPSR_DATA(IP9_28_27, VI0_DATA3_VI0_B3), + PINMUX_IPSR_MODSEL_DATA(IP9_28_27, SCIF3_SCK_B, SEL_SCIF3_1), + PINMUX_IPSR_MODSEL_DATA(IP9_28_27, SCIFA3_SCK_B, SEL_SCIFA3_1), + PINMUX_IPSR_DATA(IP9_31_29, VI0_G0), + PINMUX_IPSR_MODSEL_DATA(IP9_31_29, SCL8, SEL_IIC8_0), + PINMUX_IPSR_MODSEL_DATA(IP9_31_29, STP_IVCXO27_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP9_31_29, SCL4, SEL_IIC4_0), + PINMUX_IPSR_MODSEL_DATA(IP9_31_29, HCTS2_N, SEL_HSCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP9_31_29, SCIFB2_CTS_N, SEL_SCIFB2_0), + PINMUX_IPSR_DATA(IP9_31_29, ATAWR1_N), + + /* IPSR10 */ + PINMUX_IPSR_DATA(IP10_2_0, VI0_G1), + PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SDA8, SEL_IIC8_0), + PINMUX_IPSR_MODSEL_DATA(IP10_2_0, STP_ISCLK_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SDA4, SEL_IIC4_0), + PINMUX_IPSR_MODSEL_DATA(IP10_2_0, HRTS2_N, SEL_HSCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP10_2_0, SCIFB2_RTS_N, SEL_SCIFB2_0), + PINMUX_IPSR_DATA(IP10_2_0, ATADIR1_N), + PINMUX_IPSR_DATA(IP10_5_3, VI0_G2), + PINMUX_IPSR_DATA(IP10_5_3, VI2_HSYNC_N), + PINMUX_IPSR_MODSEL_DATA(IP10_5_3, STP_ISD_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP10_5_3, SCL3_B, SEL_IIC3_1), + PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK2, SEL_HSCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP10_5_3, SCIFB2_SCK, SEL_SCIFB2_0), + PINMUX_IPSR_DATA(IP10_5_3, ATARD1_N), + PINMUX_IPSR_DATA(IP10_8_6, VI0_G3), + PINMUX_IPSR_DATA(IP10_8_6, VI2_VSYNC_N), + PINMUX_IPSR_MODSEL_DATA(IP10_8_6, STP_ISEN_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP10_8_6, SDA3_B, SEL_IIC3_1), + PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX2, SEL_HSCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP10_8_6, SCIFB2_RXD, SEL_SCIFB2_0), + PINMUX_IPSR_DATA(IP10_8_6, ATACS01_N), + PINMUX_IPSR_DATA(IP10_11_9, VI0_G4), + PINMUX_IPSR_DATA(IP10_11_9, VI2_CLKENB), + PINMUX_IPSR_MODSEL_DATA(IP10_11_9, STP_ISSYNC_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX2, SEL_HSCIF2_0), + PINMUX_IPSR_MODSEL_DATA(IP10_11_9, SCIFB2_TXD, SEL_SCIFB2_0), + PINMUX_IPSR_MODSEL_DATA(IP10_11_9, SCIFB0_SCK_D, SEL_SCIFB_3), + PINMUX_IPSR_DATA(IP10_14_12, VI0_G5), + PINMUX_IPSR_DATA(IP10_14_12, VI2_FIELD), + PINMUX_IPSR_MODSEL_DATA(IP10_14_12, STP_OPWM_0_C, SEL_SSP_2), + PINMUX_IPSR_MODSEL_DATA(IP10_14_12, FMCLK_D, SEL_FM_3), + PINMUX_IPSR_MODSEL_DATA(IP10_14_12, CAN0_TX_E, SEL_CAN0_4), + PINMUX_IPSR_MODSEL_DATA(IP10_14_12, HTX1_D, SEL_HSCIF1_3), + PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCIFB0_TXD_D, SEL_SCIFB_3), + PINMUX_IPSR_DATA(IP10_16_15, VI0_G6), + PINMUX_IPSR_DATA(IP10_16_15, VI2_CLK), + PINMUX_IPSR_MODSEL_DATA(IP10_16_15, BPFCLK_D, SEL_FM_3), + PINMUX_IPSR_DATA(IP10_18_17, VI0_G7), + PINMUX_IPSR_DATA(IP10_18_17, VI2_DATA0), + PINMUX_IPSR_MODSEL_DATA(IP10_18_17, FMIN_D, SEL_FM_3), + PINMUX_IPSR_DATA(IP10_21_19, VI0_R0), + PINMUX_IPSR_DATA(IP10_21_19, VI2_DATA1), + PINMUX_IPSR_MODSEL_DATA(IP10_21_19, GLO_I0_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TS_SDATA0_C, SEL_TSIF0_2), + PINMUX_IPSR_DATA(IP10_21_19, ATACS11_N), + PINMUX_IPSR_DATA(IP10_24_22, VI0_R1), + PINMUX_IPSR_DATA(IP10_24_22, VI2_DATA2), + PINMUX_IPSR_MODSEL_DATA(IP10_24_22, GLO_I1_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP10_24_22, TS_SCK0_C, SEL_TSIF0_2), + PINMUX_IPSR_DATA(IP10_24_22, ATAG1_N), + PINMUX_IPSR_DATA(IP10_26_25, VI0_R2), + PINMUX_IPSR_DATA(IP10_26_25, VI2_DATA3), + PINMUX_IPSR_MODSEL_DATA(IP10_26_25, GLO_Q0_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP10_26_25, TS_SDEN0_C, SEL_TSIF0_2), + PINMUX_IPSR_DATA(IP10_28_27, VI0_R3), + PINMUX_IPSR_DATA(IP10_28_27, VI2_DATA4), + PINMUX_IPSR_MODSEL_DATA(IP10_28_27, GLO_Q1_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP10_28_27, TS_SPSYNC0_C, SEL_TSIF0_2), + PINMUX_IPSR_DATA(IP10_31_29, VI0_R4), + PINMUX_IPSR_DATA(IP10_31_29, VI2_DATA5), + PINMUX_IPSR_MODSEL_DATA(IP10_31_29, GLO_SCLK_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP10_31_29, TX0_C, SEL_SCIF0_2), + PINMUX_IPSR_MODSEL_DATA(IP10_31_29, SCL1_D, SEL_IIC1_3), + + /* IPSR11 */ + PINMUX_IPSR_DATA(IP11_2_0, VI0_R5), + PINMUX_IPSR_DATA(IP11_2_0, VI2_DATA6), + PINMUX_IPSR_MODSEL_DATA(IP11_2_0, GLO_SDATA_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP11_2_0, RX0_C, SEL_SCIF0_2), + PINMUX_IPSR_MODSEL_DATA(IP11_2_0, SDA1_D, SEL_IIC1_3), + PINMUX_IPSR_DATA(IP11_5_3, VI0_R6), + PINMUX_IPSR_DATA(IP11_5_3, VI2_DATA7), + PINMUX_IPSR_MODSEL_DATA(IP11_5_3, GLO_SS_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP11_5_3, TX1_C, SEL_SCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP11_5_3, SCL4_B, SEL_IIC4_1), + PINMUX_IPSR_DATA(IP11_8_6, VI0_R7), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, GLO_RFON_B, SEL_GPS_1), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, RX1_C, SEL_SCIF1_2), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, CAN0_RX_E, SEL_CAN0_4), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, SDA4_B, SEL_IIC4_1), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, HRX1_D, SEL_HSCIF1_3), + PINMUX_IPSR_MODSEL_DATA(IP11_8_6, SCIFB0_RXD_D, SEL_SCIFB_3), + PINMUX_IPSR_MODSEL_DATA(IP11_11_9, VI1_HSYNC_N, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_11_9, AVB_RXD0), + PINMUX_IPSR_MODSEL_DATA(IP11_11_9, TS_SDATA0_B, SEL_TSIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP11_11_9, TX4_B, SEL_SCIF4_1), + PINMUX_IPSR_MODSEL_DATA(IP11_11_9, SCIFA4_TXD_B, SEL_SCIFA4_1), + PINMUX_IPSR_MODSEL_DATA(IP11_14_12, VI1_VSYNC_N, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_14_12, AVB_RXD1), + PINMUX_IPSR_MODSEL_DATA(IP11_14_12, TS_SCK0_B, SEL_TSIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP11_14_12, RX4_B, SEL_SCIF4_1), + PINMUX_IPSR_MODSEL_DATA(IP11_14_12, SCIFA4_RXD_B, SEL_SCIFA4_1), + PINMUX_IPSR_MODSEL_DATA(IP11_16_15, VI1_CLKENB, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_16_15, AVB_RXD2), + PINMUX_IPSR_MODSEL_DATA(IP11_16_15, TS_SDEN0_B, SEL_TSIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP11_18_17, VI1_FIELD, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_18_17, AVB_RXD3), + PINMUX_IPSR_MODSEL_DATA(IP11_18_17, TS_SPSYNC0_B, SEL_TSIF0_1), + PINMUX_IPSR_MODSEL_DATA(IP11_19, VI1_CLK, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_19, AVB_RXD4), + PINMUX_IPSR_MODSEL_DATA(IP11_20, VI1_DATA0, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_20, AVB_RXD5), + PINMUX_IPSR_MODSEL_DATA(IP11_21, VI1_DATA1, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_21, AVB_RXD6), + PINMUX_IPSR_MODSEL_DATA(IP11_22, VI1_DATA2, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_22, AVB_RXD7), + PINMUX_IPSR_MODSEL_DATA(IP11_23, VI1_DATA3, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_23, AVB_RX_ER), + PINMUX_IPSR_MODSEL_DATA(IP11_24, VI1_DATA4, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_24, AVB_MDIO), + PINMUX_IPSR_MODSEL_DATA(IP11_25, VI1_DATA5, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_25, AVB_RX_DV), + PINMUX_IPSR_MODSEL_DATA(IP11_26, VI1_DATA6, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_26, AVB_MAGIC), + PINMUX_IPSR_MODSEL_DATA(IP11_27, VI1_DATA7, SEL_VI1_0), + PINMUX_IPSR_DATA(IP11_27, AVB_MDC), + PINMUX_IPSR_DATA(IP11_29_28, ETH_MDIO), + PINMUX_IPSR_DATA(IP11_29_28, AVB_RX_CLK), + PINMUX_IPSR_MODSEL_DATA(IP11_29_28, SCL2_C, SEL_IIC2_2), + PINMUX_IPSR_DATA(IP11_31_30, ETH_CRS_DV), + PINMUX_IPSR_DATA(IP11_31_30, AVB_LINK), + PINMUX_IPSR_MODSEL_DATA(IP11_31_30, SDA2_C, SEL_IIC2_2), + + /* IPSR12 */ + PINMUX_IPSR_DATA(IP12_1_0, ETH_RX_ER), + PINMUX_IPSR_DATA(IP12_1_0, AVB_CRS), + PINMUX_IPSR_MODSEL_DATA(IP12_1_0, SCL3, SEL_IIC3_0), + PINMUX_IPSR_MODSEL_DATA(IP12_1_0, SCL7, SEL_IIC7_0), + PINMUX_IPSR_DATA(IP12_3_2, ETH_RXD0), + PINMUX_IPSR_DATA(IP12_3_2, AVB_PHY_INT), + PINMUX_IPSR_MODSEL_DATA(IP12_3_2, SDA3, SEL_IIC3_0), + PINMUX_IPSR_MODSEL_DATA(IP12_3_2, SDA7, SEL_IIC7_0), + PINMUX_IPSR_DATA(IP12_6_4, ETH_RXD1), + PINMUX_IPSR_DATA(IP12_6_4, AVB_GTXREFCLK), + PINMUX_IPSR_MODSEL_DATA(IP12_6_4, CAN0_TX_C, SEL_CAN0_2), + PINMUX_IPSR_MODSEL_DATA(IP12_6_4, SCL2_D, SEL_IIC2_3), + PINMUX_IPSR_MODSEL_DATA(IP12_6_4, MSIOF1_RXD_E, SEL_SOF1_4), + PINMUX_IPSR_DATA(IP12_9_7, ETH_LINK), + PINMUX_IPSR_DATA(IP12_9_7, AVB_TXD0), + PINMUX_IPSR_MODSEL_DATA(IP12_9_7, CAN0_RX_C, SEL_CAN0_2), + PINMUX_IPSR_MODSEL_DATA(IP12_9_7, SDA2_D, SEL_IIC2_3), + PINMUX_IPSR_MODSEL_DATA(IP12_9_7, MSIOF1_SCK_E, SEL_SOF1_4), + PINMUX_IPSR_DATA(IP12_12_10, ETH_REFCLK), + PINMUX_IPSR_DATA(IP12_12_10, AVB_TXD1), + PINMUX_IPSR_MODSEL_DATA(IP12_12_10, SCIFA3_RXD_B, SEL_SCIFA3_1), + PINMUX_IPSR_MODSEL_DATA(IP12_12_10, CAN1_RX_C, SEL_CAN1_2), + PINMUX_IPSR_MODSEL_DATA(IP12_12_10, MSIOF1_SYNC_E, SEL_SOF1_4), + PINMUX_IPSR_DATA(IP12_15_13, ETH_TXD1), + PINMUX_IPSR_DATA(IP12_15_13, AVB_TXD2), + PINMUX_IPSR_MODSEL_DATA(IP12_15_13, SCIFA3_TXD_B, SEL_SCIFA3_1), + PINMUX_IPSR_MODSEL_DATA(IP12_15_13, CAN1_TX_C, SEL_CAN1_2), + PINMUX_IPSR_MODSEL_DATA(IP12_15_13, MSIOF1_TXD_E, SEL_SOF1_4), + PINMUX_IPSR_DATA(IP12_17_16, ETH_TX_EN), + PINMUX_IPSR_DATA(IP12_17_16, AVB_TXD3), + PINMUX_IPSR_MODSEL_DATA(IP12_17_16, TCLK1_B, SEL_TMU1_0), + PINMUX_IPSR_MODSEL_DATA(IP12_17_16, CAN_CLK_B, SEL_CANCLK_1), + PINMUX_IPSR_DATA(IP12_19_18, ETH_MAGIC), + PINMUX_IPSR_DATA(IP12_19_18, AVB_TXD4), + PINMUX_IPSR_MODSEL_DATA(IP12_19_18, IETX_C, SEL_IEB_2), + PINMUX_IPSR_DATA(IP12_21_20, ETH_TXD0), + PINMUX_IPSR_DATA(IP12_21_20, AVB_TXD5), + PINMUX_IPSR_MODSEL_DATA(IP12_21_20, IECLK_C, SEL_IEB_2), + PINMUX_IPSR_DATA(IP12_23_22, ETH_MDC), + PINMUX_IPSR_DATA(IP12_23_22, AVB_TXD6), + PINMUX_IPSR_MODSEL_DATA(IP12_23_22, IERX_C, SEL_IEB_2), + PINMUX_IPSR_MODSEL_DATA(IP12_26_24, STP_IVCXO27_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP12_26_24, AVB_TXD7), + PINMUX_IPSR_MODSEL_DATA(IP12_26_24, SCIFB2_TXD_D, SEL_SCIFB2_3), + PINMUX_IPSR_MODSEL_DATA(IP12_26_24, ADIDATA_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP12_26_24, MSIOF0_SYNC_C, SEL_SOF0_2), + PINMUX_IPSR_MODSEL_DATA(IP12_29_27, STP_ISCLK_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP12_29_27, AVB_TX_EN), + PINMUX_IPSR_MODSEL_DATA(IP12_29_27, SCIFB2_RXD_D, SEL_SCIFB2_3), + PINMUX_IPSR_MODSEL_DATA(IP12_29_27, ADICS_SAMP_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP12_29_27, MSIOF0_SCK_C, SEL_SOF0_2), + + /* IPSR13 */ + PINMUX_IPSR_MODSEL_DATA(IP13_2_0, STP_ISD_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP13_2_0, AVB_TX_ER), + PINMUX_IPSR_MODSEL_DATA(IP13_2_0, SCIFB2_SCK_C, SEL_SCIFB2_2), + PINMUX_IPSR_MODSEL_DATA(IP13_2_0, ADICLK_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP13_2_0, MSIOF0_SS1_C, SEL_SOF0_2), + PINMUX_IPSR_MODSEL_DATA(IP13_4_3, STP_ISEN_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP13_4_3, AVB_TX_CLK), + PINMUX_IPSR_MODSEL_DATA(IP13_4_3, ADICHS0_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP13_4_3, MSIOF0_SS2_C, SEL_SOF0_2), + PINMUX_IPSR_MODSEL_DATA(IP13_6_5, STP_ISSYNC_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP13_6_5, AVB_COL), + PINMUX_IPSR_MODSEL_DATA(IP13_6_5, ADICHS1_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP13_6_5, MSIOF0_RXD_C, SEL_SOF0_2), + PINMUX_IPSR_MODSEL_DATA(IP13_9_7, STP_OPWM_0, SEL_SSP_0), + PINMUX_IPSR_DATA(IP13_9_7, AVB_GTX_CLK), + PINMUX_IPSR_DATA(IP13_9_7, PWM0_B), + PINMUX_IPSR_MODSEL_DATA(IP13_9_7, ADICHS2_B, SEL_RAD_1), + PINMUX_IPSR_MODSEL_DATA(IP13_9_7, MSIOF0_TXD_C, SEL_SOF0_2), + PINMUX_IPSR_DATA(IP13_10, SD0_CLK), + PINMUX_IPSR_MODSEL_DATA(IP13_10, SPCLK_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_11, SD0_CMD), + PINMUX_IPSR_MODSEL_DATA(IP13_11, MOSI_IO0_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_12, SD0_DATA0), + PINMUX_IPSR_MODSEL_DATA(IP13_12, MISO_IO1_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_13, SD0_DATA1), + PINMUX_IPSR_MODSEL_DATA(IP13_13, IO2_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_14, SD0_DATA2), + PINMUX_IPSR_MODSEL_DATA(IP13_14, IO3_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_15, SD0_DATA3), + PINMUX_IPSR_MODSEL_DATA(IP13_15, SSL_B, SEL_QSP_1), + PINMUX_IPSR_DATA(IP13_18_16, SD0_CD), + PINMUX_IPSR_MODSEL_DATA(IP13_18_16, MMC_D6_B, SEL_MMC_1), + PINMUX_IPSR_MODSEL_DATA(IP13_18_16, SIM0_RST_B, SEL_SIM_1), + PINMUX_IPSR_MODSEL_DATA(IP13_18_16, CAN0_RX_F, SEL_CAN0_5), + PINMUX_IPSR_MODSEL_DATA(IP13_18_16, SCIFA5_TXD_B, SEL_SCIFA5_1), + PINMUX_IPSR_MODSEL_DATA(IP13_18_16, TX3_C, SEL_SCIF3_2), + PINMUX_IPSR_DATA(IP13_21_19, SD0_WP), + PINMUX_IPSR_MODSEL_DATA(IP13_21_19, MMC_D7_B, SEL_MMC_1), + PINMUX_IPSR_MODSEL_DATA(IP13_21_19, SIM0_D_B, SEL_SIM_1), + PINMUX_IPSR_MODSEL_DATA(IP13_21_19, CAN0_TX_F, SEL_CAN0_5), + PINMUX_IPSR_MODSEL_DATA(IP13_21_19, SCIFA5_RXD_B, SEL_SCIFA5_1), + PINMUX_IPSR_MODSEL_DATA(IP13_21_19, RX3_C, SEL_SCIF3_2), + PINMUX_IPSR_DATA(IP13_22, SD1_CMD), + PINMUX_IPSR_MODSEL_DATA(IP13_22, REMOCON_B, SEL_RCN_1), + PINMUX_IPSR_DATA(IP13_24_23, SD1_DATA0), + PINMUX_IPSR_MODSEL_DATA(IP13_24_23, SPEEDIN_B, SEL_RSP_1), + PINMUX_IPSR_DATA(IP13_25, SD1_DATA1), + PINMUX_IPSR_MODSEL_DATA(IP13_25, IETX_B, SEL_IEB_1), + PINMUX_IPSR_DATA(IP13_26, SD1_DATA2), + PINMUX_IPSR_MODSEL_DATA(IP13_26, IECLK_B, SEL_IEB_1), + PINMUX_IPSR_DATA(IP13_27, SD1_DATA3), + PINMUX_IPSR_MODSEL_DATA(IP13_27, IERX_B, SEL_IEB_1), + PINMUX_IPSR_DATA(IP13_30_28, SD1_CD), + PINMUX_IPSR_DATA(IP13_30_28, PWM0), + PINMUX_IPSR_DATA(IP13_30_28, TPU_TO0), + PINMUX_IPSR_MODSEL_DATA(IP13_30_28, SCL1_C, SEL_IIC1_2), + + /* IPSR14 */ + PINMUX_IPSR_DATA(IP14_1_0, SD1_WP), + PINMUX_IPSR_DATA(IP14_1_0, PWM1_B), + PINMUX_IPSR_MODSEL_DATA(IP14_1_0, SDA1_C, SEL_IIC1_2), + PINMUX_IPSR_DATA(IP14_2, SD2_CLK), + PINMUX_IPSR_DATA(IP14_2, MMC_CLK), + PINMUX_IPSR_DATA(IP14_3, SD2_CMD), + PINMUX_IPSR_DATA(IP14_3, MMC_CMD), + PINMUX_IPSR_DATA(IP14_4, SD2_DATA0), + PINMUX_IPSR_DATA(IP14_4, MMC_D0), + PINMUX_IPSR_DATA(IP14_5, SD2_DATA1), + PINMUX_IPSR_DATA(IP14_5, MMC_D1), + PINMUX_IPSR_DATA(IP14_6, SD2_DATA2), + PINMUX_IPSR_DATA(IP14_6, MMC_D2), + PINMUX_IPSR_DATA(IP14_7, SD2_DATA3), + PINMUX_IPSR_DATA(IP14_7, MMC_D3), + PINMUX_IPSR_DATA(IP14_10_8, SD2_CD), + PINMUX_IPSR_DATA(IP14_10_8, MMC_D4), + PINMUX_IPSR_MODSEL_DATA(IP14_10_8, SCL8_C, SEL_IIC8_2), + PINMUX_IPSR_MODSEL_DATA(IP14_10_8, TX5_B, SEL_SCIF5_1), + PINMUX_IPSR_MODSEL_DATA(IP14_10_8, SCIFA5_TXD_C, SEL_SCIFA5_2), + PINMUX_IPSR_DATA(IP14_13_11, SD2_WP), + PINMUX_IPSR_DATA(IP14_13_11, MMC_D5), + PINMUX_IPSR_MODSEL_DATA(IP14_13_11, SDA8_C, SEL_IIC8_2), + PINMUX_IPSR_MODSEL_DATA(IP14_13_11, RX5_B, SEL_SCIF5_1), + PINMUX_IPSR_MODSEL_DATA(IP14_13_11, SCIFA5_RXD_C, SEL_SCIFA5_2), + PINMUX_IPSR_MODSEL_DATA(IP14_16_14, MSIOF0_SCK, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_16_14, RX2_C, SEL_SCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP14_16_14, ADIDATA, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_16_14, VI1_CLK_C, SEL_VI1_2), + PINMUX_IPSR_DATA(IP14_16_14, VI1_G0_B), + PINMUX_IPSR_MODSEL_DATA(IP14_19_17, MSIOF0_SYNC, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_19_17, TX2_C, SEL_SCIF2_2), + PINMUX_IPSR_MODSEL_DATA(IP14_19_17, ADICS_SAMP, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_19_17, VI1_CLKENB_C, SEL_VI1_2), + PINMUX_IPSR_DATA(IP14_19_17, VI1_G1_B), + PINMUX_IPSR_MODSEL_DATA(IP14_22_20, MSIOF0_TXD, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_22_20, ADICLK, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_22_20, VI1_FIELD_C, SEL_VI1_2), + PINMUX_IPSR_DATA(IP14_22_20, VI1_G2_B), + PINMUX_IPSR_MODSEL_DATA(IP14_25_23, MSIOF0_RXD, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_25_23, ADICHS0, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_25_23, VI1_DATA0_C, SEL_VI1_2), + PINMUX_IPSR_DATA(IP14_25_23, VI1_G3_B), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, MSIOF0_SS1, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, MMC_D6, SEL_MMC_0), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, ADICHS1, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, TX0_E, SEL_SCIF0_4), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, VI1_HSYNC_N_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP14_28_26, SCL7_C, SEL_IIC7_2), + PINMUX_IPSR_DATA(IP14_28_26, VI1_G4_B), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, MSIOF0_SS2, SEL_SOF0_0), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, MMC_D7, SEL_MMC_0), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, ADICHS2, SEL_RAD_0), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, RX0_E, SEL_SCIF0_4), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, VI1_VSYNC_N_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP14_31_29, SDA7_C, SEL_IIC7_2), + PINMUX_IPSR_DATA(IP14_31_29, VI1_G5_B), + + /* IPSR15 */ + PINMUX_IPSR_MODSEL_DATA(IP15_1_0, SIM0_RST, SEL_SIM_0), + PINMUX_IPSR_MODSEL_DATA(IP15_1_0, IETX, SEL_IEB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_1_0, CAN1_TX_D, SEL_CAN1_3), + PINMUX_IPSR_DATA(IP15_3_2, SIM0_CLK), + PINMUX_IPSR_MODSEL_DATA(IP15_3_2, IECLK, SEL_IEB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_3_2, CAN_CLK_C, SEL_CANCLK_2), + PINMUX_IPSR_MODSEL_DATA(IP15_5_4, SIM0_D, SEL_SIM_0), + PINMUX_IPSR_MODSEL_DATA(IP15_5_4, IERX, SEL_IEB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_5_4, CAN1_RX_D, SEL_CAN1_3), + PINMUX_IPSR_MODSEL_DATA(IP15_8_6, GPS_CLK, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP15_8_6, DU1_DOTCLKIN_C, SEL_DIS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_8_6, AUDIO_CLKB_B, SEL_ADG_1), + PINMUX_IPSR_DATA(IP15_8_6, PWM5_B), + PINMUX_IPSR_MODSEL_DATA(IP15_8_6, SCIFA3_TXD_C, SEL_SCIFA3_2), + PINMUX_IPSR_MODSEL_DATA(IP15_11_9, GPS_SIGN, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP15_11_9, TX4_C, SEL_SCIF4_2), + PINMUX_IPSR_MODSEL_DATA(IP15_11_9, SCIFA4_TXD_C, SEL_SCIFA4_2), + PINMUX_IPSR_DATA(IP15_11_9, PWM5), + PINMUX_IPSR_DATA(IP15_11_9, VI1_G6_B), + PINMUX_IPSR_MODSEL_DATA(IP15_11_9, SCIFA3_RXD_C, SEL_SCIFA3_2), + PINMUX_IPSR_MODSEL_DATA(IP15_14_12, GPS_MAG, SEL_GPS_0), + PINMUX_IPSR_MODSEL_DATA(IP15_14_12, RX4_C, SEL_SCIF4_2), + PINMUX_IPSR_MODSEL_DATA(IP15_14_12, SCIFA4_RXD_C, SEL_SCIFA4_2), + PINMUX_IPSR_DATA(IP15_14_12, PWM6), + PINMUX_IPSR_DATA(IP15_14_12, VI1_G7_B), + PINMUX_IPSR_MODSEL_DATA(IP15_14_12, SCIFA3_SCK_C, SEL_SCIFA3_2), + PINMUX_IPSR_MODSEL_DATA(IP15_17_15, HCTS0_N, SEL_HSCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP15_17_15, SCIFB0_CTS_N, SEL_SCIFB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_17_15, GLO_I0_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_17_15, TCLK1, SEL_TMU1_0), + PINMUX_IPSR_MODSEL_DATA(IP15_17_15, VI1_DATA1_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP15_20_18, HRTS0_N, SEL_HSCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP15_20_18, SCIFB0_RTS_N, SEL_SCIFB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_20_18, GLO_I1_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_20_18, VI1_DATA2_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP15_23_21, HSCK0, SEL_HSCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP15_23_21, SCIFB0_SCK, SEL_SCIFB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_23_21, GLO_Q0_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_23_21, CAN_CLK, SEL_CANCLK_0), + PINMUX_IPSR_DATA(IP15_23_21, TCLK2), + PINMUX_IPSR_MODSEL_DATA(IP15_23_21, VI1_DATA3_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP15_26_24, HRX0, SEL_HSCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP15_26_24, SCIFB0_RXD, SEL_SCIFB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_26_24, GLO_Q1_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_26_24, CAN0_RX_B, SEL_CAN0_1), + PINMUX_IPSR_MODSEL_DATA(IP15_26_24, VI1_DATA4_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP15_29_27, HTX0, SEL_HSCIF0_0), + PINMUX_IPSR_MODSEL_DATA(IP15_29_27, SCIFB0_TXD, SEL_SCIFB_0), + PINMUX_IPSR_MODSEL_DATA(IP15_29_27, GLO_SCLK_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP15_29_27, CAN0_TX_B, SEL_CAN0_1), + PINMUX_IPSR_MODSEL_DATA(IP15_29_27, VI1_DATA5_C, SEL_VI1_2), + + /* IPSR16 */ + PINMUX_IPSR_MODSEL_DATA(IP16_2_0, HRX1, SEL_HSCIF1_0), + PINMUX_IPSR_MODSEL_DATA(IP16_2_0, SCIFB1_RXD, SEL_SCIFB1_0), + PINMUX_IPSR_DATA(IP16_2_0, VI1_R0_B), + PINMUX_IPSR_MODSEL_DATA(IP16_2_0, GLO_SDATA_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP16_2_0, VI1_DATA6_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP16_5_3, HTX1, SEL_HSCIF1_0), + PINMUX_IPSR_MODSEL_DATA(IP16_5_3, SCIFB1_TXD, SEL_SCIFB1_0), + PINMUX_IPSR_DATA(IP16_5_3, VI1_R1_B), + PINMUX_IPSR_MODSEL_DATA(IP16_5_3, GLO_SS_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP16_5_3, VI1_DATA7_C, SEL_VI1_2), + PINMUX_IPSR_MODSEL_DATA(IP16_7_6, HSCK1, SEL_HSCIF1_0), + PINMUX_IPSR_MODSEL_DATA(IP16_7_6, SCIFB1_SCK, SEL_SCIFB1_0), + PINMUX_IPSR_DATA(IP16_7_6, MLB_CK), + PINMUX_IPSR_MODSEL_DATA(IP16_7_6, GLO_RFON_C, SEL_GPS_2), + PINMUX_IPSR_MODSEL_DATA(IP16_9_8, HCTS1_N, SEL_HSCIF1_0), + PINMUX_IPSR_DATA(IP16_9_8, SCIFB1_CTS_N), + PINMUX_IPSR_DATA(IP16_9_8, MLB_SIG), + PINMUX_IPSR_MODSEL_DATA(IP16_9_8, CAN1_TX_B, SEL_CAN1_1), + PINMUX_IPSR_MODSEL_DATA(IP16_11_10, HRTS1_N, SEL_HSCIF1_0), + PINMUX_IPSR_DATA(IP16_11_10, SCIFB1_RTS_N), + PINMUX_IPSR_DATA(IP16_11_10, MLB_DAT), + PINMUX_IPSR_MODSEL_DATA(IP16_11_10, CAN1_RX_B, SEL_CAN1_1), +}; + +static struct sh_pfc_pin pinmux_pins[] = { + PINMUX_GPIO_GP_ALL(), +}; + +/* - DU --------------------------------------------------------------------- */ +static const unsigned int du_rgb666_pins[] = { + /* R[7:2], G[7:2], B[7:2] */ + RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 5), + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 2), + RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 13), + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 10), + RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 21), + RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 19), RCAR_GP_PIN(3, 18), +}; +static const unsigned int du_rgb666_mux[] = { + DU1_DR7_MARK, DU1_DR6_MARK, DU1_DR5_MARK, DU1_DR4_MARK, + DU1_DR3_MARK, DU1_DR2_MARK, + DU1_DG7_MARK, DU1_DG6_MARK, DU1_DG5_MARK, DU1_DG4_MARK, + DU1_DG3_MARK, DU1_DG2_MARK, + DU1_DB7_MARK, DU1_DB6_MARK, DU1_DB5_MARK, DU1_DB4_MARK, + DU1_DB3_MARK, DU1_DB2_MARK, +}; +static const unsigned int du_rgb888_pins[] = { + /* R[7:0], G[7:0], B[7:0] */ + RCAR_GP_PIN(3, 7), RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 5), + RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 2), + RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 0), + RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 13), + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 11), RCAR_GP_PIN(3, 10), + RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 8), + RCAR_GP_PIN(3, 23), RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 21), + RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 19), RCAR_GP_PIN(3, 18), + RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 16), +}; +static const unsigned int du_rgb888_mux[] = { + DU1_DR7_MARK, DU1_DR6_MARK, DU1_DR5_MARK, DU1_DR4_MARK, + DU1_DR3_MARK, DU1_DR2_MARK, DU1_DR1_MARK, DU1_DR0_MARK, + DU1_DG7_MARK, DU1_DG6_MARK, DU1_DG5_MARK, DU1_DG4_MARK, + DU1_DG3_MARK, DU1_DG2_MARK, DU1_DG1_MARK, DU1_DG0_MARK, + DU1_DB7_MARK, DU1_DB6_MARK, DU1_DB5_MARK, DU1_DB4_MARK, + DU1_DB3_MARK, DU1_DB2_MARK, DU1_DB1_MARK, DU1_DB0_MARK, +}; +static const unsigned int du_clk_out_0_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(3, 25), +}; +static const unsigned int du_clk_out_0_mux[] = { + DU1_DOTCLKOUT0_MARK +}; +static const unsigned int du_clk_out_1_pins[] = { + /* CLKOUT */ + RCAR_GP_PIN(3, 26), +}; +static const unsigned int du_clk_out_1_mux[] = { + DU1_DOTCLKOUT1_MARK +}; +static const unsigned int du_sync_1_pins[] = { + /* EXVSYNC/VSYNC, EXHSYNC/HSYNC, EXDISP/EXODDF/EXCDE */ + RCAR_GP_PIN(3, 29), RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 27), +}; +static const unsigned int du_sync_1_mux[] = { + DU1_EXODDF_DU1_ODDF_DISP_CDE_MARK, + DU1_EXVSYNC_DU1_VSYNC_MARK, DU1_EXHSYNC_DU1_HSYNC_MARK +}; +static const unsigned int du_cde_disp_pins[] = { + /* CDE DISP */ + RCAR_GP_PIN(3, 31), RCAR_GP_PIN(3, 30), +}; +static const unsigned int du0_clk_in_pins[] = { + /* CLKIN */ + RCAR_GP_PIN(6, 31), +}; +static const unsigned int du0_clk_in_mux[] = { + DU0_DOTCLKIN_MARK +}; +static const unsigned int du_cde_disp_mux[] = { + DU1_CDE_MARK, DU1_DISP_MARK +}; +static const unsigned int du1_clk_in_pins[] = { + /* CLKIN */ + RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 19), RCAR_GP_PIN(3, 24), +}; +static const unsigned int du1_clk_in_mux[] = { + DU1_DOTCLKIN_C_MARK, DU1_DOTCLKIN_B_MARK, DU1_DOTCLKIN_MARK +}; +/* - ETH -------------------------------------------------------------------- */ +static const unsigned int eth_link_pins[] = { + /* LINK */ + RCAR_GP_PIN(5, 18), +}; +static const unsigned int eth_link_mux[] = { + ETH_LINK_MARK, +}; +static const unsigned int eth_magic_pins[] = { + /* MAGIC */ + RCAR_GP_PIN(5, 22), +}; +static const unsigned int eth_magic_mux[] = { + ETH_MAGIC_MARK, +}; +static const unsigned int eth_mdio_pins[] = { + /* MDC, MDIO */ + RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 13), +}; +static const unsigned int eth_mdio_mux[] = { + ETH_MDC_MARK, ETH_MDIO_MARK, +}; +static const unsigned int eth_rmii_pins[] = { + /* RXD[0:1], RX_ER, CRS_DV, TXD[0:1], TX_EN, REF_CLK */ + RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 17), RCAR_GP_PIN(5, 15), + RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 23), RCAR_GP_PIN(5, 20), + RCAR_GP_PIN(5, 21), RCAR_GP_PIN(5, 19), +}; +static const unsigned int eth_rmii_mux[] = { + ETH_RXD0_MARK, ETH_RXD1_MARK, ETH_RX_ER_MARK, ETH_CRS_DV_MARK, + ETH_TXD0_MARK, ETH_TXD1_MARK, ETH_TX_EN_MARK, ETH_REFCLK_MARK, +}; +/* - INTC ------------------------------------------------------------------- */ +static const unsigned int intc_irq0_pins[] = { + /* IRQ */ + RCAR_GP_PIN(7, 10), +}; +static const unsigned int intc_irq0_mux[] = { + IRQ0_MARK, +}; +static const unsigned int intc_irq1_pins[] = { + /* IRQ */ + RCAR_GP_PIN(7, 11), +}; +static const unsigned int intc_irq1_mux[] = { + IRQ1_MARK, +}; +static const unsigned int intc_irq2_pins[] = { + /* IRQ */ + RCAR_GP_PIN(7, 12), +}; +static const unsigned int intc_irq2_mux[] = { + IRQ2_MARK, +}; +static const unsigned int intc_irq3_pins[] = { + /* IRQ */ + RCAR_GP_PIN(7, 13), +}; +static const unsigned int intc_irq3_mux[] = { + IRQ3_MARK, +}; +/* - MMCIF ------------------------------------------------------------------ */ +static const unsigned int mmc_data1_pins[] = { + /* D[0] */ + RCAR_GP_PIN(6, 18), +}; +static const unsigned int mmc_data1_mux[] = { + MMC_D0_MARK, +}; +static const unsigned int mmc_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19), + RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21), +}; +static const unsigned int mmc_data4_mux[] = { + MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK, +}; +static const unsigned int mmc_data8_pins[] = { + /* D[0:7] */ + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19), + RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21), + RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23), + RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 29), +}; +static const unsigned int mmc_data8_mux[] = { + MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK, + MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK, +}; +static const unsigned int mmc_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 17), +}; +static const unsigned int mmc_ctrl_mux[] = { + MMC_CLK_MARK, MMC_CMD_MARK, +}; +/* - MSIOF0 ----------------------------------------------------------------- */ +static const unsigned int msiof0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(6, 24), +}; +static const unsigned int msiof0_clk_mux[] = { + MSIOF0_SCK_MARK, +}; +static const unsigned int msiof0_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(6, 25), +}; +static const unsigned int msiof0_sync_mux[] = { + MSIOF0_SYNC_MARK, +}; +static const unsigned int msiof0_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(6, 28), +}; +static const unsigned int msiof0_ss1_mux[] = { + MSIOF0_SS1_MARK, +}; +static const unsigned int msiof0_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(6, 29), +}; +static const unsigned int msiof0_ss2_mux[] = { + MSIOF0_SS2_MARK, +}; +static const unsigned int msiof0_rx_pins[] = { + /* RXD */ + RCAR_GP_PIN(6, 27), +}; +static const unsigned int msiof0_rx_mux[] = { + MSIOF0_RXD_MARK, +}; +static const unsigned int msiof0_tx_pins[] = { + /* TXD */ + RCAR_GP_PIN(6, 26), +}; +static const unsigned int msiof0_tx_mux[] = { + MSIOF0_TXD_MARK, +}; +/* - MSIOF1 ----------------------------------------------------------------- */ +static const unsigned int msiof1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(0, 22), +}; +static const unsigned int msiof1_clk_mux[] = { + MSIOF1_SCK_MARK, +}; +static const unsigned int msiof1_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(0, 23), +}; +static const unsigned int msiof1_sync_mux[] = { + MSIOF1_SYNC_MARK, +}; +static const unsigned int msiof1_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(0, 24), +}; +static const unsigned int msiof1_ss1_mux[] = { + MSIOF1_SS1_MARK, +}; +static const unsigned int msiof1_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(0, 25), +}; +static const unsigned int msiof1_ss2_mux[] = { + MSIOF1_SS2_MARK, +}; +static const unsigned int msiof1_rx_pins[] = { + /* RXD */ + RCAR_GP_PIN(0, 27), +}; +static const unsigned int msiof1_rx_mux[] = { + MSIOF1_RXD_MARK, +}; +static const unsigned int msiof1_tx_pins[] = { + /* TXD */ + RCAR_GP_PIN(0, 26), +}; +static const unsigned int msiof1_tx_mux[] = { + MSIOF1_TXD_MARK, +}; +/* - MSIOF2 ----------------------------------------------------------------- */ +static const unsigned int msiof2_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 13), +}; +static const unsigned int msiof2_clk_mux[] = { + MSIOF2_SCK_MARK, +}; +static const unsigned int msiof2_sync_pins[] = { + /* SYNC */ + RCAR_GP_PIN(1, 14), +}; +static const unsigned int msiof2_sync_mux[] = { + MSIOF2_SYNC_MARK, +}; +static const unsigned int msiof2_ss1_pins[] = { + /* SS1 */ + RCAR_GP_PIN(1, 17), +}; +static const unsigned int msiof2_ss1_mux[] = { + MSIOF2_SS1_MARK, +}; +static const unsigned int msiof2_ss2_pins[] = { + /* SS2 */ + RCAR_GP_PIN(1, 18), +}; +static const unsigned int msiof2_ss2_mux[] = { + MSIOF2_SS2_MARK, +}; +static const unsigned int msiof2_rx_pins[] = { + /* RXD */ + RCAR_GP_PIN(1, 16), +}; +static const unsigned int msiof2_rx_mux[] = { + MSIOF2_RXD_MARK, +}; +static const unsigned int msiof2_tx_pins[] = { + /* TXD */ + RCAR_GP_PIN(1, 15), +}; +static const unsigned int msiof2_tx_mux[] = { + MSIOF2_TXD_MARK, +}; +/* - SCIF0 ------------------------------------------------------------------ */ +static const unsigned int scif0_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), +}; +static const unsigned int scif0_data_mux[] = { + RX0_MARK, TX0_MARK, +}; +static const unsigned int scif0_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 0), +}; +static const unsigned int scif0_data_b_mux[] = { + RX0_B_MARK, TX0_B_MARK, +}; +static const unsigned int scif0_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(4, 26), RCAR_GP_PIN(4, 25), +}; +static const unsigned int scif0_data_c_mux[] = { + RX0_C_MARK, TX0_C_MARK, +}; +static const unsigned int scif0_data_d_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 23), RCAR_GP_PIN(2, 22), +}; +static const unsigned int scif0_data_d_mux[] = { + RX0_D_MARK, TX0_D_MARK, +}; +static const unsigned int scif0_data_e_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 29), RCAR_GP_PIN(6, 28), +}; +static const unsigned int scif0_data_e_mux[] = { + RX0_E_MARK, TX0_E_MARK, +}; +/* - SCIF1 ------------------------------------------------------------------ */ +static const unsigned int scif1_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), +}; +static const unsigned int scif1_data_mux[] = { + RX1_MARK, TX1_MARK, +}; +static const unsigned int scif1_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 8), +}; +static const unsigned int scif1_data_b_mux[] = { + RX1_B_MARK, TX1_B_MARK, +}; +static const unsigned int scif1_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 10), +}; +static const unsigned int scif1_clk_b_mux[] = { + SCIF1_SCK_B_MARK, +}; +static const unsigned int scif1_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 27), +}; +static const unsigned int scif1_data_c_mux[] = { + RX1_C_MARK, TX1_C_MARK, +}; +static const unsigned int scif1_data_d_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 25), RCAR_GP_PIN(2, 24), +}; +static const unsigned int scif1_data_d_mux[] = { + RX1_D_MARK, TX1_D_MARK, +}; +/* - SCIF2 ------------------------------------------------------------------ */ +static const unsigned int scif2_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 30), RCAR_GP_PIN(2, 31), +}; +static const unsigned int scif2_data_mux[] = { + RX2_MARK, TX2_MARK, +}; +static const unsigned int scif2_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 16), +}; +static const unsigned int scif2_data_b_mux[] = { + RX2_B_MARK, TX2_B_MARK, +}; +static const unsigned int scif2_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 18), +}; +static const unsigned int scif2_clk_b_mux[] = { + SCIF2_SCK_B_MARK, +}; +static const unsigned int scif2_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25), +}; +static const unsigned int scif2_data_c_mux[] = { + RX2_C_MARK, TX2_C_MARK, +}; +static const unsigned int scif2_data_e_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8), +}; +static const unsigned int scif2_data_e_mux[] = { + RX2_E_MARK, TX2_E_MARK, +}; +/* - SCIF3 ------------------------------------------------------------------ */ +static const unsigned int scif3_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 21), +}; +static const unsigned int scif3_data_mux[] = { + RX3_MARK, TX3_MARK, +}; +static const unsigned int scif3_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 23), +}; +static const unsigned int scif3_clk_mux[] = { + SCIF3_SCK_MARK, +}; +static const unsigned int scif3_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(3, 29), RCAR_GP_PIN(3, 26), +}; +static const unsigned int scif3_data_b_mux[] = { + RX3_B_MARK, TX3_B_MARK, +}; +static const unsigned int scif3_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 8), +}; +static const unsigned int scif3_clk_b_mux[] = { + SCIF3_SCK_B_MARK, +}; +static const unsigned int scif3_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6), +}; +static const unsigned int scif3_data_c_mux[] = { + RX3_C_MARK, TX3_C_MARK, +}; +static const unsigned int scif3_data_d_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(2, 27), RCAR_GP_PIN(2, 26), +}; +static const unsigned int scif3_data_d_mux[] = { + RX3_D_MARK, TX3_D_MARK, +}; +/* - SCIF4 ------------------------------------------------------------------ */ +static const unsigned int scif4_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 1), +}; +static const unsigned int scif4_data_mux[] = { + RX4_MARK, TX4_MARK, +}; +static const unsigned int scif4_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0), +}; +static const unsigned int scif4_data_b_mux[] = { + RX4_B_MARK, TX4_B_MARK, +}; +static const unsigned int scif4_data_c_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 21), +}; +static const unsigned int scif4_data_c_mux[] = { + RX4_C_MARK, TX4_C_MARK, +}; +/* - SCIF5 ------------------------------------------------------------------ */ +static const unsigned int scif5_data_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 3), +}; +static const unsigned int scif5_data_mux[] = { + RX5_MARK, TX5_MARK, +}; +static const unsigned int scif5_data_b_pins[] = { + /* RX, TX */ + RCAR_GP_PIN(6, 23), RCAR_GP_PIN(6, 22), +}; +static const unsigned int scif5_data_b_mux[] = { + RX5_B_MARK, TX5_B_MARK, +}; +/* - SCIFA0 ----------------------------------------------------------------- */ +static const unsigned int scifa0_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), +}; +static const unsigned int scifa0_data_mux[] = { + SCIFA0_RXD_MARK, SCIFA0_TXD_MARK, +}; +static const unsigned int scifa0_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 0), +}; +static const unsigned int scifa0_data_b_mux[] = { + SCIFA0_RXD_B_MARK, SCIFA0_TXD_B_MARK +}; +/* - SCIFA1 ----------------------------------------------------------------- */ +static const unsigned int scifa1_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), +}; +static const unsigned int scifa1_data_mux[] = { + SCIFA1_RXD_MARK, SCIFA1_TXD_MARK, +}; +static const unsigned int scifa1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 10), +}; +static const unsigned int scifa1_clk_mux[] = { + SCIFA1_SCK_MARK, +}; +static const unsigned int scifa1_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 8), +}; +static const unsigned int scifa1_data_b_mux[] = { + SCIFA1_RXD_B_MARK, SCIFA1_TXD_B_MARK, +}; +static const unsigned int scifa1_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 0), +}; +static const unsigned int scifa1_clk_b_mux[] = { + SCIFA1_SCK_B_MARK, +}; +static const unsigned int scifa1_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), +}; +static const unsigned int scifa1_data_c_mux[] = { + SCIFA1_RXD_C_MARK, SCIFA1_TXD_C_MARK, +}; +/* - SCIFA2 ----------------------------------------------------------------- */ +static const unsigned int scifa2_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(2, 30), RCAR_GP_PIN(2, 31), +}; +static const unsigned int scifa2_data_mux[] = { + SCIFA2_RXD_MARK, SCIFA2_TXD_MARK, +}; +static const unsigned int scifa2_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 18), +}; +static const unsigned int scifa2_clk_mux[] = { + SCIFA2_SCK_MARK, +}; +static const unsigned int scifa2_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(3, 17), RCAR_GP_PIN(3, 16), +}; +static const unsigned int scifa2_data_b_mux[] = { + SCIFA2_RXD_B_MARK, SCIFA2_TXD_B_MARK, +}; +/* - SCIFA3 ----------------------------------------------------------------- */ +static const unsigned int scifa3_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 21), +}; +static const unsigned int scifa3_data_mux[] = { + SCIFA3_RXD_MARK, SCIFA3_TXD_MARK, +}; +static const unsigned int scifa3_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(3, 23), +}; +static const unsigned int scifa3_clk_mux[] = { + SCIFA3_SCK_MARK, +}; +static const unsigned int scifa3_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 20), +}; +static const unsigned int scifa3_data_b_mux[] = { + SCIFA3_RXD_B_MARK, SCIFA3_TXD_B_MARK, +}; +static const unsigned int scifa3_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 8), +}; +static const unsigned int scifa3_clk_b_mux[] = { + SCIFA3_SCK_B_MARK, +}; +static const unsigned int scifa3_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(7, 21), RCAR_GP_PIN(7, 20), +}; +static const unsigned int scifa3_data_c_mux[] = { + SCIFA3_RXD_C_MARK, SCIFA3_TXD_C_MARK, +}; +static const unsigned int scifa3_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(7, 22), +}; +static const unsigned int scifa3_clk_c_mux[] = { + SCIFA3_SCK_C_MARK, +}; +/* - SCIFA4 ----------------------------------------------------------------- */ +static const unsigned int scifa4_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 1), +}; +static const unsigned int scifa4_data_mux[] = { + SCIFA4_RXD_MARK, SCIFA4_TXD_MARK, +}; +static const unsigned int scifa4_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0), +}; +static const unsigned int scifa4_data_b_mux[] = { + SCIFA4_RXD_B_MARK, SCIFA4_TXD_B_MARK, +}; +static const unsigned int scifa4_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 21), +}; +static const unsigned int scifa4_data_c_mux[] = { + SCIFA4_RXD_C_MARK, SCIFA4_TXD_C_MARK, +}; +/* - SCIFA5 ----------------------------------------------------------------- */ +static const unsigned int scifa5_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 3), +}; +static const unsigned int scifa5_data_mux[] = { + SCIFA5_RXD_MARK, SCIFA5_TXD_MARK, +}; +static const unsigned int scifa5_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6), +}; +static const unsigned int scifa5_data_b_mux[] = { + SCIFA5_RXD_B_MARK, SCIFA5_TXD_B_MARK, +}; +static const unsigned int scifa5_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(6, 23), RCAR_GP_PIN(6, 22), +}; +static const unsigned int scifa5_data_c_mux[] = { + SCIFA5_RXD_C_MARK, SCIFA5_TXD_C_MARK, +}; +/* - SCIFB0 ----------------------------------------------------------------- */ +static const unsigned int scifb0_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(7, 3), RCAR_GP_PIN(7, 4), +}; +static const unsigned int scifb0_data_mux[] = { + SCIFB0_RXD_MARK, SCIFB0_TXD_MARK, +}; +static const unsigned int scifb0_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(7, 2), +}; +static const unsigned int scifb0_clk_mux[] = { + SCIFB0_SCK_MARK, +}; +static const unsigned int scifb0_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(7, 1), RCAR_GP_PIN(7, 0), +}; +static const unsigned int scifb0_ctrl_mux[] = { + SCIFB0_RTS_N_MARK, SCIFB0_CTS_N_MARK, +}; +static const unsigned int scifb0_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 20), RCAR_GP_PIN(1, 21), +}; +static const unsigned int scifb0_data_b_mux[] = { + SCIFB0_RXD_B_MARK, SCIFB0_TXD_B_MARK, +}; +static const unsigned int scifb0_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 31), +}; +static const unsigned int scifb0_clk_b_mux[] = { + SCIFB0_SCK_B_MARK, +}; +static const unsigned int scifb0_ctrl_b_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(1, 22), RCAR_GP_PIN(1, 23), +}; +static const unsigned int scifb0_ctrl_b_mux[] = { + SCIFB0_RTS_N_B_MARK, SCIFB0_CTS_N_B_MARK, +}; +static const unsigned int scifb0_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int scifb0_data_c_mux[] = { + SCIFB0_RXD_C_MARK, SCIFB0_TXD_C_MARK, +}; +static const unsigned int scifb0_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(2, 30), +}; +static const unsigned int scifb0_clk_c_mux[] = { + SCIFB0_SCK_C_MARK, +}; +static const unsigned int scifb0_data_d_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 18), +}; +static const unsigned int scifb0_data_d_mux[] = { + SCIFB0_RXD_D_MARK, SCIFB0_TXD_D_MARK, +}; +static const unsigned int scifb0_clk_d_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 17), +}; +static const unsigned int scifb0_clk_d_mux[] = { + SCIFB0_SCK_D_MARK, +}; +/* - SCIFB1 ----------------------------------------------------------------- */ +static const unsigned int scifb1_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(7, 5), RCAR_GP_PIN(7, 6), +}; +static const unsigned int scifb1_data_mux[] = { + SCIFB1_RXD_MARK, SCIFB1_TXD_MARK, +}; +static const unsigned int scifb1_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(7, 7), +}; +static const unsigned int scifb1_clk_mux[] = { + SCIFB1_SCK_MARK, +}; +static const unsigned int scifb1_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(7, 9), RCAR_GP_PIN(7, 8), +}; +static const unsigned int scifb1_ctrl_mux[] = { + SCIFB1_RTS_N_MARK, SCIFB1_CTS_N_MARK, +}; +static const unsigned int scifb1_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 17), RCAR_GP_PIN(1, 18), +}; +static const unsigned int scifb1_data_b_mux[] = { + SCIFB1_RXD_B_MARK, SCIFB1_TXD_B_MARK, +}; +static const unsigned int scifb1_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(1, 3), +}; +static const unsigned int scifb1_clk_b_mux[] = { + SCIFB1_SCK_B_MARK, +}; +static const unsigned int scifb1_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), +}; +static const unsigned int scifb1_data_c_mux[] = { + SCIFB1_RXD_C_MARK, SCIFB1_TXD_C_MARK, +}; +static const unsigned int scifb1_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(7, 11), +}; +static const unsigned int scifb1_clk_c_mux[] = { + SCIFB1_SCK_C_MARK, +}; +static const unsigned int scifb1_data_d_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(7, 10), RCAR_GP_PIN(7, 12), +}; +static const unsigned int scifb1_data_d_mux[] = { + SCIFB1_RXD_D_MARK, SCIFB1_TXD_D_MARK, +}; +/* - SCIFB2 ----------------------------------------------------------------- */ +static const unsigned int scifb2_data_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(4, 16), RCAR_GP_PIN(4, 17), +}; +static const unsigned int scifb2_data_mux[] = { + SCIFB2_RXD_MARK, SCIFB2_TXD_MARK, +}; +static const unsigned int scifb2_clk_pins[] = { + /* SCK */ + RCAR_GP_PIN(4, 15), +}; +static const unsigned int scifb2_clk_mux[] = { + SCIFB2_SCK_MARK, +}; +static const unsigned int scifb2_ctrl_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(4, 14), RCAR_GP_PIN(4, 13), +}; +static const unsigned int scifb2_ctrl_mux[] = { + SCIFB2_RTS_N_MARK, SCIFB2_CTS_N_MARK, +}; +static const unsigned int scifb2_data_b_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13), +}; +static const unsigned int scifb2_data_b_mux[] = { + SCIFB2_RXD_B_MARK, SCIFB2_TXD_B_MARK, +}; +static const unsigned int scifb2_clk_b_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 31), +}; +static const unsigned int scifb2_clk_b_mux[] = { + SCIFB2_SCK_B_MARK, +}; +static const unsigned int scifb2_ctrl_b_pins[] = { + /* RTS, CTS */ + RCAR_GP_PIN(3, 15), RCAR_GP_PIN(3, 14), +}; +static const unsigned int scifb2_ctrl_b_mux[] = { + SCIFB2_RTS_N_B_MARK, SCIFB2_CTS_N_B_MARK, +}; +static const unsigned int scifb2_data_c_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(2, 0), RCAR_GP_PIN(2, 1), +}; +static const unsigned int scifb2_data_c_mux[] = { + SCIFB2_RXD_C_MARK, SCIFB2_TXD_C_MARK, +}; +static const unsigned int scifb2_clk_c_pins[] = { + /* SCK */ + RCAR_GP_PIN(5, 27), +}; +static const unsigned int scifb2_clk_c_mux[] = { + SCIFB2_SCK_C_MARK, +}; +static const unsigned int scifb2_data_d_pins[] = { + /* RXD, TXD */ + RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 25), +}; +static const unsigned int scifb2_data_d_mux[] = { + SCIFB2_RXD_D_MARK, SCIFB2_TXD_D_MARK, +}; +/* - SDHI0 ------------------------------------------------------------------ */ +static const unsigned int sdhi0_data1_pins[] = { + /* D0 */ + RCAR_GP_PIN(6, 2), +}; +static const unsigned int sdhi0_data1_mux[] = { + SD0_DATA0_MARK, +}; +static const unsigned int sdhi0_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(6, 2), RCAR_GP_PIN(6, 3), + RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 5), +}; +static const unsigned int sdhi0_data4_mux[] = { + SD0_DATA0_MARK, SD0_DATA1_MARK, SD0_DATA2_MARK, SD0_DATA3_MARK, +}; +static const unsigned int sdhi0_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(6, 0), RCAR_GP_PIN(6, 1), +}; +static const unsigned int sdhi0_ctrl_mux[] = { + SD0_CLK_MARK, SD0_CMD_MARK, +}; +static const unsigned int sdhi0_cd_pins[] = { + /* CD */ + RCAR_GP_PIN(6, 6), +}; +static const unsigned int sdhi0_cd_mux[] = { + SD0_CD_MARK, +}; +static const unsigned int sdhi0_wp_pins[] = { + /* WP */ + RCAR_GP_PIN(6, 7), +}; +static const unsigned int sdhi0_wp_mux[] = { + SD0_WP_MARK, +}; +/* - SDHI1 ------------------------------------------------------------------ */ +static const unsigned int sdhi1_data1_pins[] = { + /* D0 */ + RCAR_GP_PIN(6, 10), +}; +static const unsigned int sdhi1_data1_mux[] = { + SD1_DATA0_MARK, +}; +static const unsigned int sdhi1_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(6, 10), RCAR_GP_PIN(6, 11), + RCAR_GP_PIN(6, 12), RCAR_GP_PIN(6, 13), +}; +static const unsigned int sdhi1_data4_mux[] = { + SD1_DATA0_MARK, SD1_DATA1_MARK, SD1_DATA2_MARK, SD1_DATA3_MARK, +}; +static const unsigned int sdhi1_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9), +}; +static const unsigned int sdhi1_ctrl_mux[] = { + SD1_CLK_MARK, SD1_CMD_MARK, +}; +static const unsigned int sdhi1_cd_pins[] = { + /* CD */ + RCAR_GP_PIN(6, 14), +}; +static const unsigned int sdhi1_cd_mux[] = { + SD1_CD_MARK, +}; +static const unsigned int sdhi1_wp_pins[] = { + /* WP */ + RCAR_GP_PIN(6, 15), +}; +static const unsigned int sdhi1_wp_mux[] = { + SD1_WP_MARK, +}; +/* - SDHI2 ------------------------------------------------------------------ */ +static const unsigned int sdhi2_data1_pins[] = { + /* D0 */ + RCAR_GP_PIN(6, 18), +}; +static const unsigned int sdhi2_data1_mux[] = { + SD2_DATA0_MARK, +}; +static const unsigned int sdhi2_data4_pins[] = { + /* D[0:3] */ + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 19), + RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 21), +}; +static const unsigned int sdhi2_data4_mux[] = { + SD2_DATA0_MARK, SD2_DATA1_MARK, SD2_DATA2_MARK, SD2_DATA3_MARK, +}; +static const unsigned int sdhi2_ctrl_pins[] = { + /* CLK, CMD */ + RCAR_GP_PIN(6, 16), RCAR_GP_PIN(6, 17), +}; +static const unsigned int sdhi2_ctrl_mux[] = { + SD2_CLK_MARK, SD2_CMD_MARK, +}; +static const unsigned int sdhi2_cd_pins[] = { + /* CD */ + RCAR_GP_PIN(6, 22), +}; +static const unsigned int sdhi2_cd_mux[] = { + SD2_CD_MARK, +}; +static const unsigned int sdhi2_wp_pins[] = { + /* WP */ + RCAR_GP_PIN(6, 23), +}; +static const unsigned int sdhi2_wp_mux[] = { + SD2_WP_MARK, +}; +/* - USB0 ------------------------------------------------------------------- */ +static const unsigned int usb0_pwen_pins[] = { + /* PWEN */ + RCAR_GP_PIN(7, 23), +}; +static const unsigned int usb0_pwen_mux[] = { + USB0_PWEN_MARK, +}; +static const unsigned int usb0_ovc_pins[] = { + /* OVC */ + RCAR_GP_PIN(7, 24), +}; +static const unsigned int usb0_ovc_mux[] = { + USB0_OVC_MARK, +}; +/* - USB1 ------------------------------------------------------------------- */ +static const unsigned int usb1_pwen_pins[] = { + /* PWEN */ + RCAR_GP_PIN(7, 25), +}; +static const unsigned int usb1_pwen_mux[] = { + USB1_PWEN_MARK, +}; +static const unsigned int usb1_ovc_pins[] = { + /* OVC */ + RCAR_GP_PIN(6, 30), +}; +static const unsigned int usb1_ovc_mux[] = { + USB1_OVC_MARK, +}; + +static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(du_rgb666), + SH_PFC_PIN_GROUP(du_rgb888), + SH_PFC_PIN_GROUP(du_clk_out_0), + SH_PFC_PIN_GROUP(du_clk_out_1), + SH_PFC_PIN_GROUP(du_sync_1), + SH_PFC_PIN_GROUP(du_cde_disp), + SH_PFC_PIN_GROUP(du0_clk_in), + SH_PFC_PIN_GROUP(du1_clk_in), + SH_PFC_PIN_GROUP(eth_link), + SH_PFC_PIN_GROUP(eth_magic), + SH_PFC_PIN_GROUP(eth_mdio), + SH_PFC_PIN_GROUP(eth_rmii), + SH_PFC_PIN_GROUP(intc_irq0), + SH_PFC_PIN_GROUP(intc_irq1), + SH_PFC_PIN_GROUP(intc_irq2), + SH_PFC_PIN_GROUP(intc_irq3), + SH_PFC_PIN_GROUP(mmc_data1), + SH_PFC_PIN_GROUP(mmc_data4), + SH_PFC_PIN_GROUP(mmc_data8), + SH_PFC_PIN_GROUP(mmc_ctrl), + SH_PFC_PIN_GROUP(msiof0_clk), + SH_PFC_PIN_GROUP(msiof0_sync), + SH_PFC_PIN_GROUP(msiof0_ss1), + SH_PFC_PIN_GROUP(msiof0_ss2), + SH_PFC_PIN_GROUP(msiof0_rx), + SH_PFC_PIN_GROUP(msiof0_tx), + SH_PFC_PIN_GROUP(msiof1_clk), + SH_PFC_PIN_GROUP(msiof1_sync), + SH_PFC_PIN_GROUP(msiof1_ss1), + SH_PFC_PIN_GROUP(msiof1_ss2), + SH_PFC_PIN_GROUP(msiof1_rx), + SH_PFC_PIN_GROUP(msiof1_tx), + SH_PFC_PIN_GROUP(msiof2_clk), + SH_PFC_PIN_GROUP(msiof2_sync), + SH_PFC_PIN_GROUP(msiof2_ss1), + SH_PFC_PIN_GROUP(msiof2_ss2), + SH_PFC_PIN_GROUP(msiof2_rx), + SH_PFC_PIN_GROUP(msiof2_tx), + SH_PFC_PIN_GROUP(scif0_data), + SH_PFC_PIN_GROUP(scif0_data_b), + SH_PFC_PIN_GROUP(scif0_data_c), + SH_PFC_PIN_GROUP(scif0_data_d), + SH_PFC_PIN_GROUP(scif0_data_e), + SH_PFC_PIN_GROUP(scif1_data), + SH_PFC_PIN_GROUP(scif1_data_b), + SH_PFC_PIN_GROUP(scif1_clk_b), + SH_PFC_PIN_GROUP(scif1_data_c), + SH_PFC_PIN_GROUP(scif1_data_d), + SH_PFC_PIN_GROUP(scif2_data), + SH_PFC_PIN_GROUP(scif2_data_b), + SH_PFC_PIN_GROUP(scif2_clk_b), + SH_PFC_PIN_GROUP(scif2_data_c), + SH_PFC_PIN_GROUP(scif2_data_e), + SH_PFC_PIN_GROUP(scif3_data), + SH_PFC_PIN_GROUP(scif3_clk), + SH_PFC_PIN_GROUP(scif3_data_b), + SH_PFC_PIN_GROUP(scif3_clk_b), + SH_PFC_PIN_GROUP(scif3_data_c), + SH_PFC_PIN_GROUP(scif3_data_d), + SH_PFC_PIN_GROUP(scif4_data), + SH_PFC_PIN_GROUP(scif4_data_b), + SH_PFC_PIN_GROUP(scif4_data_c), + SH_PFC_PIN_GROUP(scif5_data), + SH_PFC_PIN_GROUP(scif5_data_b), + SH_PFC_PIN_GROUP(scifa0_data), + SH_PFC_PIN_GROUP(scifa0_data_b), + SH_PFC_PIN_GROUP(scifa1_data), + SH_PFC_PIN_GROUP(scifa1_clk), + SH_PFC_PIN_GROUP(scifa1_data_b), + SH_PFC_PIN_GROUP(scifa1_clk_b), + SH_PFC_PIN_GROUP(scifa1_data_c), + SH_PFC_PIN_GROUP(scifa2_data), + SH_PFC_PIN_GROUP(scifa2_clk), + SH_PFC_PIN_GROUP(scifa2_data_b), + SH_PFC_PIN_GROUP(scifa3_data), + SH_PFC_PIN_GROUP(scifa3_clk), + SH_PFC_PIN_GROUP(scifa3_data_b), + SH_PFC_PIN_GROUP(scifa3_clk_b), + SH_PFC_PIN_GROUP(scifa3_data_c), + SH_PFC_PIN_GROUP(scifa3_clk_c), + SH_PFC_PIN_GROUP(scifa4_data), + SH_PFC_PIN_GROUP(scifa4_data_b), + SH_PFC_PIN_GROUP(scifa4_data_c), + SH_PFC_PIN_GROUP(scifa5_data), + SH_PFC_PIN_GROUP(scifa5_data_b), + SH_PFC_PIN_GROUP(scifa5_data_c), + SH_PFC_PIN_GROUP(scifb0_data), + SH_PFC_PIN_GROUP(scifb0_clk), + SH_PFC_PIN_GROUP(scifb0_ctrl), + SH_PFC_PIN_GROUP(scifb0_data_b), + SH_PFC_PIN_GROUP(scifb0_clk_b), + SH_PFC_PIN_GROUP(scifb0_ctrl_b), + SH_PFC_PIN_GROUP(scifb0_data_c), + SH_PFC_PIN_GROUP(scifb0_clk_c), + SH_PFC_PIN_GROUP(scifb0_data_d), + SH_PFC_PIN_GROUP(scifb0_clk_d), + SH_PFC_PIN_GROUP(scifb1_data), + SH_PFC_PIN_GROUP(scifb1_clk), + SH_PFC_PIN_GROUP(scifb1_ctrl), + SH_PFC_PIN_GROUP(scifb1_data_b), + SH_PFC_PIN_GROUP(scifb1_clk_b), + SH_PFC_PIN_GROUP(scifb1_data_c), + SH_PFC_PIN_GROUP(scifb1_clk_c), + SH_PFC_PIN_GROUP(scifb1_data_d), + SH_PFC_PIN_GROUP(scifb2_data), + SH_PFC_PIN_GROUP(scifb2_clk), + SH_PFC_PIN_GROUP(scifb2_ctrl), + SH_PFC_PIN_GROUP(scifb2_data_b), + SH_PFC_PIN_GROUP(scifb2_clk_b), + SH_PFC_PIN_GROUP(scifb2_ctrl_b), + SH_PFC_PIN_GROUP(scifb2_data_c), + SH_PFC_PIN_GROUP(scifb2_clk_c), + SH_PFC_PIN_GROUP(scifb2_data_d), + SH_PFC_PIN_GROUP(sdhi0_data1), + SH_PFC_PIN_GROUP(sdhi0_data4), + SH_PFC_PIN_GROUP(sdhi0_ctrl), + SH_PFC_PIN_GROUP(sdhi0_cd), + SH_PFC_PIN_GROUP(sdhi0_wp), + SH_PFC_PIN_GROUP(sdhi1_data1), + SH_PFC_PIN_GROUP(sdhi1_data4), + SH_PFC_PIN_GROUP(sdhi1_ctrl), + SH_PFC_PIN_GROUP(sdhi1_cd), + SH_PFC_PIN_GROUP(sdhi1_wp), + SH_PFC_PIN_GROUP(sdhi2_data1), + SH_PFC_PIN_GROUP(sdhi2_data4), + SH_PFC_PIN_GROUP(sdhi2_ctrl), + SH_PFC_PIN_GROUP(sdhi2_cd), + SH_PFC_PIN_GROUP(sdhi2_wp), + SH_PFC_PIN_GROUP(usb0_pwen), + SH_PFC_PIN_GROUP(usb0_ovc), + SH_PFC_PIN_GROUP(usb1_pwen), + SH_PFC_PIN_GROUP(usb1_ovc), +}; + +static const char * const du_groups[] = { + "du_rgb666", + "du_rgb888", + "du_clk_out_0", + "du_clk_out_1", + "du_sync_1", + "du_cde_disp", +}; + +static const char * const du0_groups[] = { + "du0_clk_in", +}; + +static const char * const du1_groups[] = { + "du1_clk_in", +}; + +static const char * const eth_groups[] = { + "eth_link", + "eth_magic", + "eth_mdio", + "eth_rmii", +}; + +static const char * const intc_groups[] = { + "intc_irq0", + "intc_irq1", + "intc_irq2", + "intc_irq3", +}; + +static const char * const mmc_groups[] = { + "mmc_data1", + "mmc_data4", + "mmc_data8", + "mmc_ctrl", +}; + +static const char * const msiof0_groups[] = { + "msiof0_clk", + "msiof0_ctrl", + "msiof0_data", +}; + +static const char * const msiof1_groups[] = { + "msiof1_clk", + "msiof1_ctrl", + "msiof1_data", +}; + +static const char * const msiof2_groups[] = { + "msiof2_clk", + "msiof2_ctrl", + "msiof2_data", +}; + +static const char * const scif0_groups[] = { + "scif0_data", + "scif0_data_b", + "scif0_data_c", + "scif0_data_d", + "scif0_data_e", +}; + +static const char * const scif1_groups[] = { + "scif1_data", + "scif1_data_b", + "scif1_clk_b", + "scif1_data_c", + "scif1_data_d", +}; + +static const char * const scif2_groups[] = { + "scif2_data", + "scif2_data_b", + "scif2_clk_b", + "scif2_data_c", + "scif2_data_e", +}; +static const char * const scif3_groups[] = { + "scif3_data", + "scif3_clk", + "scif3_data_b", + "scif3_clk_b", + "scif3_data_c", + "scif3_data_d", +}; +static const char * const scif4_groups[] = { + "scif4_data", + "scif4_data_b", + "scif4_data_c", +}; +static const char * const scif5_groups[] = { + "scif5_data", + "scif5_data_b", +}; +static const char * const scifa0_groups[] = { + "scifa0_data", + "scifa0_data_b", +}; +static const char * const scifa1_groups[] = { + "scifa1_data", + "scifa1_clk", + "scifa1_data_b", + "scifa1_clk_b", + "scifa1_data_c", +}; +static const char * const scifa2_groups[] = { + "scifa2_data", + "scifa2_clk", + "scifa2_data_b", +}; +static const char * const scifa3_groups[] = { + "scifa3_data", + "scifa3_clk", + "scifa3_data_b", + "scifa3_clk_b", + "scifa3_data_c", + "scifa3_clk_c", +}; +static const char * const scifa4_groups[] = { + "scifa4_data", + "scifa4_data_b", + "scifa4_data_c", +}; +static const char * const scifa5_groups[] = { + "scifa5_data", + "scifa5_data_b", + "scifa5_data_c", +}; +static const char * const scifb0_groups[] = { + "scifb0_data", + "scifb0_clk", + "scifb0_ctrl", + "scifb0_data_b", + "scifb0_clk_b", + "scifb0_ctrl_b", + "scifb0_data_c", + "scifb0_clk_c", + "scifb0_data_d", + "scifb0_clk_d", +}; +static const char * const scifb1_groups[] = { + "scifb1_data", + "scifb1_clk", + "scifb1_ctrl", + "scifb1_data_b", + "scifb1_clk_b", + "scifb1_data_c", + "scifb1_clk_c", + "scifb1_data_d", +}; +static const char * const scifb2_groups[] = { + "scifb2_data", + "scifb2_clk", + "scifb2_ctrl", + "scifb2_data_b", + "scifb2_clk_b", + "scifb2_ctrl_b", + "scifb0_data_c", + "scifb2_clk_c", + "scifb2_data_d", +}; + +static const char * const sdhi0_groups[] = { + "sdhi0_data1", + "sdhi0_data4", + "sdhi0_ctrl", + "sdhi0_cd", + "sdhi0_wp", +}; + +static const char * const sdhi1_groups[] = { + "sdhi1_data1", + "sdhi1_data4", + "sdhi1_ctrl", + "sdhi1_cd", + "sdhi1_wp", +}; + +static const char * const sdhi2_groups[] = { + "sdhi2_data1", + "sdhi2_data4", + "sdhi2_ctrl", + "sdhi2_cd", + "sdhi2_wp", +}; + +static const char * const usb0_groups[] = { + "usb0_pwen", + "usb0_ovc", +}; +static const char * const usb1_groups[] = { + "usb1_pwen", + "usb1_ovc", +}; + +static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(du), + SH_PFC_FUNCTION(du0), + SH_PFC_FUNCTION(du1), + SH_PFC_FUNCTION(eth), + SH_PFC_FUNCTION(intc), + SH_PFC_FUNCTION(mmc), + SH_PFC_FUNCTION(msiof0), + SH_PFC_FUNCTION(msiof1), + SH_PFC_FUNCTION(msiof2), + SH_PFC_FUNCTION(scif0), + SH_PFC_FUNCTION(scif1), + SH_PFC_FUNCTION(scif2), + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(scif5), + SH_PFC_FUNCTION(scifa0), + SH_PFC_FUNCTION(scifa1), + SH_PFC_FUNCTION(scifa2), + SH_PFC_FUNCTION(scifa3), + SH_PFC_FUNCTION(scifa4), + SH_PFC_FUNCTION(scifa5), + SH_PFC_FUNCTION(scifb0), + SH_PFC_FUNCTION(scifb1), + SH_PFC_FUNCTION(scifb2), + SH_PFC_FUNCTION(sdhi0), + SH_PFC_FUNCTION(sdhi1), + SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(usb0), + SH_PFC_FUNCTION(usb1), +}; + +static struct pinmux_cfg_reg pinmux_config_regs[] = { + { PINMUX_CFG_REG("GPSR0", 0xE6060004, 32, 1) { + GP_0_31_FN, FN_IP1_22_20, + GP_0_30_FN, FN_IP1_19_17, + GP_0_29_FN, FN_IP1_16_14, + GP_0_28_FN, FN_IP1_13_11, + GP_0_27_FN, FN_IP1_10_8, + GP_0_26_FN, FN_IP1_7_6, + GP_0_25_FN, FN_IP1_5_4, + GP_0_24_FN, FN_IP1_3_2, + GP_0_23_FN, FN_IP1_1_0, + GP_0_22_FN, FN_IP0_30_29, + GP_0_21_FN, FN_IP0_28_27, + GP_0_20_FN, FN_IP0_26_25, + GP_0_19_FN, FN_IP0_24_23, + GP_0_18_FN, FN_IP0_22_21, + GP_0_17_FN, FN_IP0_20_19, + GP_0_16_FN, FN_IP0_18_16, + GP_0_15_FN, FN_IP0_15, + GP_0_14_FN, FN_IP0_14, + GP_0_13_FN, FN_IP0_13, + GP_0_12_FN, FN_IP0_12, + GP_0_11_FN, FN_IP0_11, + GP_0_10_FN, FN_IP0_10, + GP_0_9_FN, FN_IP0_9, + GP_0_8_FN, FN_IP0_8, + GP_0_7_FN, FN_IP0_7, + GP_0_6_FN, FN_IP0_6, + GP_0_5_FN, FN_IP0_5, + GP_0_4_FN, FN_IP0_4, + GP_0_3_FN, FN_IP0_3, + GP_0_2_FN, FN_IP0_2, + GP_0_1_FN, FN_IP0_1, + GP_0_0_FN, FN_IP0_0, } + }, + { PINMUX_CFG_REG("GPSR1", 0xE6060008, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_1_25_FN, FN_IP3_21_20, + GP_1_24_FN, FN_IP3_19_18, + GP_1_23_FN, FN_IP3_17_16, + GP_1_22_FN, FN_IP3_15_14, + GP_1_21_FN, FN_IP3_13_12, + GP_1_20_FN, FN_IP3_11_9, + GP_1_19_FN, FN_RD_N, + GP_1_18_FN, FN_IP3_8_6, + GP_1_17_FN, FN_IP3_5_3, + GP_1_16_FN, FN_IP3_2_0, + GP_1_15_FN, FN_IP2_29_27, + GP_1_14_FN, FN_IP2_26_25, + GP_1_13_FN, FN_IP2_24_23, + GP_1_12_FN, FN_EX_CS0_N, + GP_1_11_FN, FN_IP2_22_21, + GP_1_10_FN, FN_IP2_20_19, + GP_1_9_FN, FN_IP2_18_16, + GP_1_8_FN, FN_IP2_15_13, + GP_1_7_FN, FN_IP2_12_10, + GP_1_6_FN, FN_IP2_9_7, + GP_1_5_FN, FN_IP2_6_5, + GP_1_4_FN, FN_IP2_4_3, + GP_1_3_FN, FN_IP2_2_0, + GP_1_2_FN, FN_IP1_31_29, + GP_1_1_FN, FN_IP1_28_26, + GP_1_0_FN, FN_IP1_25_23, } + }, + { PINMUX_CFG_REG("GPSR2", 0xE606000C, 32, 1) { + GP_2_31_FN, FN_IP6_7_6, + GP_2_30_FN, FN_IP6_5_3, + GP_2_29_FN, FN_IP6_2_0, + GP_2_28_FN, FN_AUDIO_CLKA, + GP_2_27_FN, FN_IP5_31_29, + GP_2_26_FN, FN_IP5_28_26, + GP_2_25_FN, FN_IP5_25_24, + GP_2_24_FN, FN_IP5_23_22, + GP_2_23_FN, FN_IP5_21_20, + GP_2_22_FN, FN_IP5_19_17, + GP_2_21_FN, FN_IP5_16_15, + GP_2_20_FN, FN_IP5_14_12, + GP_2_19_FN, FN_IP5_11_9, + GP_2_18_FN, FN_IP5_8_6, + GP_2_17_FN, FN_IP5_5_3, + GP_2_16_FN, FN_IP5_2_0, + GP_2_15_FN, FN_IP4_30_28, + GP_2_14_FN, FN_IP4_27_26, + GP_2_13_FN, FN_IP4_25_24, + GP_2_12_FN, FN_IP4_23_22, + GP_2_11_FN, FN_IP4_21, + GP_2_10_FN, FN_IP4_20, + GP_2_9_FN, FN_IP4_19, + GP_2_8_FN, FN_IP4_18_16, + GP_2_7_FN, FN_IP4_15_13, + GP_2_6_FN, FN_IP4_12_10, + GP_2_5_FN, FN_IP4_9_8, + GP_2_4_FN, FN_IP4_7_5, + GP_2_3_FN, FN_IP4_4_2, + GP_2_2_FN, FN_IP4_1_0, + GP_2_1_FN, FN_IP3_30_28, + GP_2_0_FN, FN_IP3_27_25 } + }, + { PINMUX_CFG_REG("GPSR3", 0xE6060010, 32, 1) { + GP_3_31_FN, FN_IP9_18_17, + GP_3_30_FN, FN_IP9_16, + GP_3_29_FN, FN_IP9_15_13, + GP_3_28_FN, FN_IP9_12, + GP_3_27_FN, FN_IP9_11, + GP_3_26_FN, FN_IP9_10_8, + GP_3_25_FN, FN_IP9_7, + GP_3_24_FN, FN_IP9_6, + GP_3_23_FN, FN_IP9_5_3, + GP_3_22_FN, FN_IP9_2_0, + GP_3_21_FN, FN_IP8_30_28, + GP_3_20_FN, FN_IP8_27_26, + GP_3_19_FN, FN_IP8_25_24, + GP_3_18_FN, FN_IP8_23_21, + GP_3_17_FN, FN_IP8_20_18, + GP_3_16_FN, FN_IP8_17_15, + GP_3_15_FN, FN_IP8_14_12, + GP_3_14_FN, FN_IP8_11_9, + GP_3_13_FN, FN_IP8_8_6, + GP_3_12_FN, FN_IP8_5_3, + GP_3_11_FN, FN_IP8_2_0, + GP_3_10_FN, FN_IP7_29_27, + GP_3_9_FN, FN_IP7_26_24, + GP_3_8_FN, FN_IP7_23_21, + GP_3_7_FN, FN_IP7_20_19, + GP_3_6_FN, FN_IP7_18_17, + GP_3_5_FN, FN_IP7_16_15, + GP_3_4_FN, FN_IP7_14_13, + GP_3_3_FN, FN_IP7_12_11, + GP_3_2_FN, FN_IP7_10_9, + GP_3_1_FN, FN_IP7_8_6, + GP_3_0_FN, FN_IP7_5_3 } + }, + { PINMUX_CFG_REG("GPSR4", 0xE6060014, 32, 1) { + GP_4_31_FN, FN_IP15_5_4, + GP_4_30_FN, FN_IP15_3_2, + GP_4_29_FN, FN_IP15_1_0, + GP_4_28_FN, FN_IP11_8_6, + GP_4_27_FN, FN_IP11_5_3, + GP_4_26_FN, FN_IP11_2_0, + GP_4_25_FN, FN_IP10_31_29, + GP_4_24_FN, FN_IP10_28_27, + GP_4_23_FN, FN_IP10_26_25, + GP_4_22_FN, FN_IP10_24_22, + GP_4_21_FN, FN_IP10_21_19, + GP_4_20_FN, FN_IP10_18_17, + GP_4_19_FN, FN_IP10_16_15, + GP_4_18_FN, FN_IP10_14_12, + GP_4_17_FN, FN_IP10_11_9, + GP_4_16_FN, FN_IP10_8_6, + GP_4_15_FN, FN_IP10_5_3, + GP_4_14_FN, FN_IP10_2_0, + GP_4_13_FN, FN_IP9_31_29, + GP_4_12_FN, FN_VI0_DATA7_VI0_B7, + GP_4_11_FN, FN_VI0_DATA6_VI0_B6, + GP_4_10_FN, FN_VI0_DATA5_VI0_B5, + GP_4_9_FN, FN_VI0_DATA4_VI0_B4, + GP_4_8_FN, FN_IP9_28_27, + GP_4_7_FN, FN_VI0_DATA2_VI0_B2, + GP_4_6_FN, FN_VI0_DATA1_VI0_B1, + GP_4_5_FN, FN_VI0_DATA0_VI0_B0, + GP_4_4_FN, FN_IP9_26_25, + GP_4_3_FN, FN_IP9_24_23, + GP_4_2_FN, FN_IP9_22_21, + GP_4_1_FN, FN_IP9_20_19, + GP_4_0_FN, FN_VI0_CLK } + }, + { PINMUX_CFG_REG("GPSR5", 0xE6060018, 32, 1) { + GP_5_31_FN, FN_IP3_24_22, + GP_5_30_FN, FN_IP13_9_7, + GP_5_29_FN, FN_IP13_6_5, + GP_5_28_FN, FN_IP13_4_3, + GP_5_27_FN, FN_IP13_2_0, + GP_5_26_FN, FN_IP12_29_27, + GP_5_25_FN, FN_IP12_26_24, + GP_5_24_FN, FN_IP12_23_22, + GP_5_23_FN, FN_IP12_21_20, + GP_5_22_FN, FN_IP12_19_18, + GP_5_21_FN, FN_IP12_17_16, + GP_5_20_FN, FN_IP12_15_13, + GP_5_19_FN, FN_IP12_12_10, + GP_5_18_FN, FN_IP12_9_7, + GP_5_17_FN, FN_IP12_6_4, + GP_5_16_FN, FN_IP12_3_2, + GP_5_15_FN, FN_IP12_1_0, + GP_5_14_FN, FN_IP11_31_30, + GP_5_13_FN, FN_IP11_29_28, + GP_5_12_FN, FN_IP11_27, + GP_5_11_FN, FN_IP11_26, + GP_5_10_FN, FN_IP11_25, + GP_5_9_FN, FN_IP11_24, + GP_5_8_FN, FN_IP11_23, + GP_5_7_FN, FN_IP11_22, + GP_5_6_FN, FN_IP11_21, + GP_5_5_FN, FN_IP11_20, + GP_5_4_FN, FN_IP11_19, + GP_5_3_FN, FN_IP11_18_17, + GP_5_2_FN, FN_IP11_16_15, + GP_5_1_FN, FN_IP11_14_12, + GP_5_0_FN, FN_IP11_11_9 } + }, + { PINMUX_CFG_REG("GPSR6", 0xE606001C, 32, 1) { + GP_6_31_FN, FN_DU0_DOTCLKIN, + GP_6_30_FN, FN_USB1_OVC, + GP_6_29_FN, FN_IP14_31_29, + GP_6_28_FN, FN_IP14_28_26, + GP_6_27_FN, FN_IP14_25_23, + GP_6_26_FN, FN_IP14_22_20, + GP_6_25_FN, FN_IP14_19_17, + GP_6_24_FN, FN_IP14_16_14, + GP_6_23_FN, FN_IP14_13_11, + GP_6_22_FN, FN_IP14_10_8, + GP_6_21_FN, FN_IP14_7, + GP_6_20_FN, FN_IP14_6, + GP_6_19_FN, FN_IP14_5, + GP_6_18_FN, FN_IP14_4, + GP_6_17_FN, FN_IP14_3, + GP_6_16_FN, FN_IP14_2, + GP_6_15_FN, FN_IP14_1_0, + GP_6_14_FN, FN_IP13_30_28, + GP_6_13_FN, FN_IP13_27, + GP_6_12_FN, FN_IP13_26, + GP_6_11_FN, FN_IP13_25, + GP_6_10_FN, FN_IP13_24_23, + GP_6_9_FN, FN_IP13_22, + 0, 0, + GP_6_7_FN, FN_IP13_21_19, + GP_6_6_FN, FN_IP13_18_16, + GP_6_5_FN, FN_IP13_15, + GP_6_4_FN, FN_IP13_14, + GP_6_3_FN, FN_IP13_13, + GP_6_2_FN, FN_IP13_12, + GP_6_1_FN, FN_IP13_11, + GP_6_0_FN, FN_IP13_10 } + }, + { PINMUX_CFG_REG("GPSR7", 0xE6060074, 32, 1) { + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + 0, 0, + GP_7_25_FN, FN_USB1_PWEN, + GP_7_24_FN, FN_USB0_OVC, + GP_7_23_FN, FN_USB0_PWEN, + GP_7_22_FN, FN_IP15_14_12, + GP_7_21_FN, FN_IP15_11_9, + GP_7_20_FN, FN_IP15_8_6, + GP_7_19_FN, FN_IP7_2_0, + GP_7_18_FN, FN_IP6_29_27, + GP_7_17_FN, FN_IP6_26_24, + GP_7_16_FN, FN_IP6_23_21, + GP_7_15_FN, FN_IP6_20_19, + GP_7_14_FN, FN_IP6_18_16, + GP_7_13_FN, FN_IP6_15_14, + GP_7_12_FN, FN_IP6_13_12, + GP_7_11_FN, FN_IP6_11_10, + GP_7_10_FN, FN_IP6_9_8, + GP_7_9_FN, FN_IP16_11_10, + GP_7_8_FN, FN_IP16_9_8, + GP_7_7_FN, FN_IP16_7_6, + GP_7_6_FN, FN_IP16_5_3, + GP_7_5_FN, FN_IP16_2_0, + GP_7_4_FN, FN_IP15_29_27, + GP_7_3_FN, FN_IP15_26_24, + GP_7_2_FN, FN_IP15_23_21, + GP_7_1_FN, FN_IP15_20_18, + GP_7_0_FN, FN_IP15_17_15 } + }, + { PINMUX_CFG_REG_VAR("IPSR0", 0xE6060020, 32, + 1, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1) { + /* IP0_31 [1] */ + 0, 0, + /* IP0_30_29 [2] */ + FN_A6, FN_MSIOF1_SCK, + 0, 0, + /* IP0_28_27 [2] */ + FN_A5, FN_MSIOF0_RXD_B, + 0, 0, + /* IP0_26_25 [2] */ + FN_A4, FN_MSIOF0_TXD_B, + 0, 0, + /* IP0_24_23 [2] */ + FN_A3, FN_MSIOF0_SS2_B, + 0, 0, + /* IP0_22_21 [2] */ + FN_A2, FN_MSIOF0_SS1_B, + 0, 0, + /* IP0_20_19 [2] */ + FN_A1, FN_MSIOF0_SYNC_B, + 0, 0, + /* IP0_18_16 [3] */ + FN_A0, FN_ATAWR0_N_C, FN_MSIOF0_SCK_B, FN_SCL0_C, FN_PWM2_B, + 0, 0, 0, + /* IP0_15 [1] */ + FN_D15, 0, + /* IP0_14 [1] */ + FN_D14, 0, + /* IP0_13 [1] */ + FN_D13, 0, + /* IP0_12 [1] */ + FN_D12, 0, + /* IP0_11 [1] */ + FN_D11, 0, + /* IP0_10 [1] */ + FN_D10, 0, + /* IP0_9 [1] */ + FN_D9, 0, + /* IP0_8 [1] */ + FN_D8, 0, + /* IP0_7 [1] */ + FN_D7, 0, + /* IP0_6 [1] */ + FN_D6, 0, + /* IP0_5 [1] */ + FN_D5, 0, + /* IP0_4 [1] */ + FN_D4, 0, + /* IP0_3 [1] */ + FN_D3, 0, + /* IP0_2 [1] */ + FN_D2, 0, + /* IP0_1 [1] */ + FN_D1, 0, + /* IP0_0 [1] */ + FN_D0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR1", 0xE6060024, 32, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2) { + /* IP1_31_29 [3] */ + FN_A18, FN_DREQ1, FN_SCIFA1_RXD_C, 0, FN_SCIFB1_RXD_C, + 0, 0, 0, + /* IP1_28_26 [3] */ + FN_A17, FN_DACK2_B, 0, FN_SDA0_C, + 0, 0, 0, 0, + /* IP1_25_23 [3] */ + FN_A16, FN_DREQ2_B, FN_FMCLK_C, 0, FN_SCIFA1_SCK_B, + 0, 0, 0, + /* IP1_22_20 [3] */ + FN_A15, FN_BPFCLK_C, + 0, 0, 0, 0, 0, 0, + /* IP1_19_17 [3] */ + FN_A14, FN_ATADIR0_N_C, FN_FMIN, FN_FMIN_C, FN_MSIOF1_SYNC_D, + 0, 0, 0, + /* IP1_16_14 [3] */ + FN_A13, FN_ATAG0_N_C, FN_BPFCLK, FN_MSIOF1_SS1_D, + 0, 0, 0, 0, + /* IP1_13_11 [3] */ + FN_A12, FN_FMCLK, FN_SDA3_D, FN_MSIOF1_SCK_D, + 0, 0, 0, 0, + /* IP1_10_8 [3] */ + FN_A11, FN_MSIOF1_RXD, FN_SCL3_D, FN_MSIOF1_RXD_D, + 0, 0, 0, 0, + /* IP1_7_6 [2] */ + FN_A10, FN_MSIOF1_TXD, 0, FN_MSIOF1_TXD_D, + /* IP1_5_4 [2] */ + FN_A9, FN_MSIOF1_SS2, FN_SDA0, 0, + /* IP1_3_2 [2] */ + FN_A8, FN_MSIOF1_SS1, FN_SCL0, 0, + /* IP1_1_0 [2] */ + FN_A7, FN_MSIOF1_SYNC, + 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR2", 0xE6060028, 32, + 2, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 3) { + /* IP2_31_20 [2] */ + 0, 0, 0, 0, + /* IP2_29_27 [3] */ + FN_EX_CS3_N, FN_ATADIR0_N, FN_MSIOF2_TXD, + FN_ATAG0_N, 0, FN_EX_WAIT1, + 0, 0, + /* IP2_26_25 [2] */ + FN_EX_CS2_N, FN_ATAWR0_N, FN_MSIOF2_SYNC, 0, + /* IP2_24_23 [2] */ + FN_EX_CS1_N, FN_MSIOF2_SCK, 0, 0, + /* IP2_22_21 [2] */ + FN_CS1_N_A26, FN_ATADIR0_N_B, FN_SDA1, 0, + /* IP2_20_19 [2] */ + FN_CS0_N, FN_ATAG0_N_B, FN_SCL1, 0, + /* IP2_18_16 [3] */ + FN_A25, FN_DACK2, FN_SSL, FN_DREQ1_C, FN_RX1, FN_SCIFA1_RXD, + 0, 0, + /* IP2_15_13 [3] */ + FN_A24, FN_DREQ2, FN_IO3, FN_TX1, FN_SCIFA1_TXD, + 0, 0, 0, + /* IP2_12_0 [3] */ + FN_A23, FN_IO2, FN_BPFCLK_B, FN_RX0, FN_SCIFA0_RXD, + 0, 0, 0, + /* IP2_9_7 [3] */ + FN_A22, FN_MISO_IO1, FN_FMCLK_B, FN_TX0, FN_SCIFA0_TXD, + 0, 0, 0, + /* IP2_6_5 [2] */ + FN_A21, FN_ATAWR0_N_B, FN_MOSI_IO0, 0, + /* IP2_4_3 [2] */ + FN_A20, FN_SPCLK, 0, 0, + /* IP2_2_0 [3] */ + FN_A19, FN_DACK1, FN_SCIFA1_TXD_C, 0, + FN_SCIFB1_TXD_C, 0, FN_SCIFB1_SCK_B, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR3", 0xE606002C, 32, + 1, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3) { + /* IP3_31 [1] */ + 0, 0, + /* IP3_30_28 [3] */ + FN_SSI_WS0129, FN_HTX0_C, FN_HTX2_C, + FN_SCIFB0_TXD_C, FN_SCIFB2_TXD_C, + 0, 0, 0, + /* IP3_27_25 [3] */ + FN_SSI_SCK0129, FN_HRX0_C, FN_HRX2_C, + FN_SCIFB0_RXD_C, FN_SCIFB2_RXD_C, + 0, 0, 0, + /* IP3_24_22 [3] */ + FN_SPEEDIN, 0, FN_HSCK0_C, FN_HSCK2_C, FN_SCIFB0_SCK_B, + FN_SCIFB2_SCK_B, FN_DREQ2_C, FN_HTX2_D, + /* IP3_21_20 [2] */ + FN_DACK0, FN_DRACK0, FN_REMOCON, 0, + /* IP3_19_18 [2] */ + FN_DREQ0, FN_PWM3, FN_TPU_TO3, 0, + /* IP3_17_16 [2] */ + FN_EX_WAIT0, FN_HRTS2_N_B, FN_SCIFB0_CTS_N_B, 0, + /* IP3_15_14 [2] */ + FN_WE1_N, FN_ATARD0_N_B, FN_HTX2_B, FN_SCIFB0_RTS_N_B, + /* IP3_13_12 [2] */ + FN_WE0_N, FN_HCTS2_N_B, FN_SCIFB0_TXD_B, 0, + /* IP3_11_9 [3] */ + FN_RD_WR_N, FN_HRX2_B, FN_FMIN_B, FN_SCIFB0_RXD_B, FN_DREQ1_D, + 0, 0, 0, + /* IP3_8_6 [3] */ + FN_BS_N, FN_ATACS10_N, FN_MSIOF2_SS2, FN_HTX1_B, + FN_SCIFB1_TXD_B, FN_PWM2, FN_TPU_TO2, 0, + /* IP3_5_3 [3] */ + FN_EX_CS5_N, FN_ATACS00_N, FN_MSIOF2_SS1, FN_HRX1_B, + FN_SCIFB1_RXD_B, FN_PWM1, FN_TPU_TO1, 0, + /* IP3_2_0 [3] */ + FN_EX_CS4_N, FN_ATARD0_N, FN_MSIOF2_RXD, 0, FN_EX_WAIT2, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR4", 0xE6060030, 32, + 1, 3, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 3, 3, 2) { + /* IP4_31 [1] */ + 0, 0, + /* IP4_30_28 [3] */ + FN_SSI_SCK5, FN_MSIOF1_SCK_C, FN_TS_SDATA0, FN_GLO_I0, + FN_MSIOF2_SYNC_D, FN_VI1_R2_B, + 0, 0, + /* IP4_27_26 [2] */ + FN_SSI_SDATA4, FN_MSIOF2_SCK_D, 0, 0, + /* IP4_25_24 [2] */ + FN_SSI_WS4, FN_GLO_RFON_D, 0, 0, + /* IP4_23_22 [2] */ + FN_SSI_SCK4, FN_GLO_SS_D, 0, 0, + /* IP4_21 [1] */ + FN_SSI_SDATA3, 0, + /* IP4_20 [1] */ + FN_SSI_WS34, 0, + /* IP4_19 [1] */ + FN_SSI_SCK34, 0, + /* IP4_18_16 [3] */ + FN_SSI_SDATA2, FN_GPS_MAG_B, FN_TX2_E, FN_HRTS1_N_E, + 0, 0, 0, 0, + /* IP4_15_13 [3] */ + FN_SSI_WS2, FN_SDA2, FN_GPS_SIGN_B, FN_RX2_E, + FN_GLO_Q1_D, FN_HCTS1_N_E, + 0, 0, + /* IP4_12_10 [3] */ + FN_SSI_SCK2, FN_SCL2, FN_GPS_CLK_B, FN_GLO_Q0_D, FN_HSCK1_E, + 0, 0, 0, + /* IP4_9_8 [2] */ + FN_SSI_SDATA1, FN_SDA1_B, FN_SDA8_B, FN_MSIOF2_RXD_C, + /* IP4_7_5 [3] */ + FN_SSI_WS1, FN_SCL1_B, FN_SCL8_B, FN_MSIOF2_TXD_C, FN_GLO_I1_D, + 0, 0, 0, + /* IP4_4_2 [3] */ + FN_SSI_SCK1, FN_SDA0_B, FN_SDA7_B, + FN_MSIOF2_SYNC_C, FN_GLO_I0_D, + 0, 0, 0, + /* IP4_1_0 [2] */ + FN_SSI_SDATA0, FN_SCL0_B, FN_SCL7_B, FN_MSIOF2_SCK_C, } + }, + { PINMUX_CFG_REG_VAR("IPSR5", 0xE6060034, 32, + 3, 3, 2, 2, 2, 3, 2, 3, 3, 3, 3, 3) { + /* IP5_31_29 [3] */ + FN_SSI_SDATA9, FN_RX3_D, FN_CAN0_RX_D, + 0, 0, 0, 0, 0, + /* IP5_28_26 [3] */ + FN_SSI_WS9, FN_TX3_D, FN_CAN0_TX_D, FN_GLO_SDATA_D, + 0, 0, 0, 0, + /* IP5_25_24 [2] */ + FN_SSI_SCK9, FN_RX1_D, FN_GLO_SCLK_D, 0, + /* IP5_23_22 [2] */ + FN_SSI_SDATA8, FN_TX1_D, FN_STP_ISSYNC_0_B, 0, + /* IP5_21_20 [2] */ + FN_SSI_SDATA7, FN_RX0_D, FN_STP_ISEN_0_B, 0, + /* IP5_19_17 [3] */ + FN_SSI_WS78, FN_TX0_D, FN_STP_ISD_0_B, FN_GLO_RFON, + 0, 0, 0, 0, + /* IP5_16_15 [2] */ + FN_SSI_SCK78, FN_STP_ISCLK_0_B, FN_GLO_SS, 0, + /* IP5_14_12 [3] */ + FN_SSI_SDATA6, FN_STP_IVCXO27_0_B, FN_GLO_SDATA, FN_VI1_R7_B, + 0, 0, 0, 0, + /* IP5_11_9 [3] */ + FN_SSI_WS6, FN_GLO_SCLK, FN_MSIOF2_SS2_D, FN_VI1_R6_B, + 0, 0, 0, 0, + /* IP5_8_6 [3] */ + FN_SSI_SCK6, FN_MSIOF1_RXD_C, FN_TS_SPSYNC0, FN_GLO_Q1, + FN_MSIOF2_RXD_D, FN_VI1_R5_B, + 0, 0, + /* IP5_5_3 [3] */ + FN_SSI_SDATA5, FN_MSIOF1_TXD_C, FN_TS_SDEN0, FN_GLO_Q0, + FN_MSIOF2_SS1_D, FN_VI1_R4_B, + 0, 0, + /* IP5_2_0 [3] */ + FN_SSI_WS5, FN_MSIOF1_SYNC_C, FN_TS_SCK0, FN_GLO_I1, + FN_MSIOF2_TXD_D, FN_VI1_R3_B, + 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR6", 0xE6060038, 32, + 2, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 3, 3) { + /* IP6_31_30 [2] */ + 0, 0, 0, 0, + /* IP6_29_27 [3] */ + FN_IRQ8, FN_HRTS1_N_C, FN_MSIOF1_RXD_B, + FN_GPS_SIGN_C, FN_GPS_SIGN_D, + 0, 0, 0, + /* IP6_26_24 [3] */ + FN_IRQ7, FN_HCTS1_N_C, FN_MSIOF1_TXD_B, + FN_GPS_CLK_C, FN_GPS_CLK_D, + 0, 0, 0, + /* IP6_23_21 [3] */ + FN_IRQ6, FN_HSCK1_C, FN_MSIOF1_SS2_B, + FN_SDA1_E, FN_MSIOF2_SYNC_E, + 0, 0, 0, + /* IP6_20_19 [2] */ + FN_IRQ5, FN_HTX1_C, FN_SCL1_E, FN_MSIOF2_SCK_E, + /* IP6_18_16 [3] */ + FN_IRQ4, FN_HRX1_C, FN_SDA4_C, FN_MSIOF2_RXD_E, FN_INTC_IRQ4_N, + 0, 0, 0, + /* IP6_15_14 [2] */ + FN_IRQ3, FN_SCL4_C, FN_MSIOF2_TXD_E, FN_INTC_IRQ3_N, + /* IP6_13_12 [2] */ + FN_IRQ2, FN_SCIFB1_TXD_D, FN_INTC_IRQ2_N, 0, + /* IP6_11_10 [2] */ + FN_IRQ1, FN_SCIFB1_SCK_C, FN_INTC_IRQ1_N, 0, + /* IP6_9_8 [2] */ + FN_IRQ0, FN_SCIFB1_RXD_D, FN_INTC_IRQ0_N, 0, + /* IP6_7_6 [2] */ + FN_AUDIO_CLKOUT, FN_MSIOF1_SS1_B, FN_TX2, FN_SCIFA2_TXD, + /* IP6_5_3 [3] */ + FN_AUDIO_CLKC, FN_SCIFB0_SCK_C, FN_MSIOF1_SYNC_B, FN_RX2, + FN_SCIFA2_RXD, FN_FMIN_E, + 0, 0, + /* IP6_2_0 [3] */ + FN_AUDIO_CLKB, FN_STP_OPWM_0_B, FN_MSIOF1_SCK_B, + FN_SCIF_CLK, 0, FN_BPFCLK_E, + 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR7", 0xE606003C, 32, + 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3) { + /* IP7_31_30 [2] */ + 0, 0, 0, 0, + /* IP7_29_27 [3] */ + FN_DU1_DG2, FN_LCDOUT10, FN_VI1_DATA4_B, FN_SCIF1_SCK_B, + FN_SCIFA1_SCK, FN_SSI_SCK78_B, + 0, 0, + /* IP7_26_24 [3] */ + FN_DU1_DG1, FN_LCDOUT9, FN_VI1_DATA3_B, FN_RX1_B, + FN_SCIFA1_RXD_B, FN_MSIOF2_SS2_B, + 0, 0, + /* IP7_23_21 [3] */ + FN_DU1_DG0, FN_LCDOUT8, FN_VI1_DATA2_B, FN_TX1_B, + FN_SCIFA1_TXD_B, FN_MSIOF2_SS1_B, + 0, 0, + /* IP7_20_19 [2] */ + FN_DU1_DR7, FN_LCDOUT7, FN_SSI_SDATA1_B, 0, + /* IP7_18_17 [2] */ + FN_DU1_DR6, FN_LCDOUT6, FN_SSI_WS1_B, 0, + /* IP7_16_15 [2] */ + FN_DU1_DR5, FN_LCDOUT5, FN_SSI_SCK1_B, 0, + /* IP7_14_13 [2] */ + FN_DU1_DR4, FN_LCDOUT4, FN_SSI_SDATA0_B, 0, + /* IP7_12_11 [2] */ + FN_DU1_DR3, FN_LCDOUT3, FN_SSI_WS0129_B, 0, + /* IP7_10_9 [2] */ + FN_DU1_DR2, FN_LCDOUT2, FN_SSI_SCK0129_B, 0, + /* IP7_8_6 [3] */ + FN_DU1_DR1, FN_LCDOUT1, FN_VI1_DATA1_B, FN_RX0_B, + FN_SCIFA0_RXD_B, FN_MSIOF2_SYNC_B, + 0, 0, + /* IP7_5_3 [3] */ + FN_DU1_DR0, FN_LCDOUT0, FN_VI1_DATA0_B, FN_TX0_B, + FN_SCIFA0_TXD_B, FN_MSIOF2_SCK_B, + 0, 0, + /* IP7_2_0 [3] */ + FN_IRQ9, FN_DU1_DOTCLKIN_B, FN_CAN_CLK_D, FN_GPS_MAG_C, + FN_SCIF_CLK_B, FN_GPS_MAG_D, + 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR8", 0xE6060040, 32, + 1, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3) { + /* IP8_31 [1] */ + 0, 0, + /* IP8_30_28 [3] */ + FN_DU1_DB5, FN_LCDOUT21, FN_TX3, FN_SCIFA3_TXD, FN_CAN1_TX, + 0, 0, 0, + /* IP8_27_26 [2] */ + FN_DU1_DB4, FN_LCDOUT20, FN_VI1_FIELD_B, FN_CAN1_RX, + /* IP8_25_24 [2] */ + FN_DU1_DB3, FN_LCDOUT19, FN_VI1_CLKENB_B, 0, + /* IP8_23_21 [3] */ + FN_DU1_DB2, FN_LCDOUT18, FN_VI1_VSYNC_N_B, FN_SCIF2_SCK_B, + FN_SCIFA2_SCK, FN_SSI_SDATA9_B, + 0, 0, + /* IP8_20_18 [3] */ + FN_DU1_DB1, FN_LCDOUT17, FN_VI1_HSYNC_N_B, FN_RX2_B, + FN_SCIFA2_RXD_B, FN_MSIOF2_RXD_B, + 0, 0, + /* IP8_17_15 [3] */ + FN_DU1_DB0, FN_LCDOUT16, FN_VI1_CLK_B, FN_TX2_B, + FN_SCIFA2_TXD_B, FN_MSIOF2_TXD_B, + 0, 0, + /* IP8_14_12 [3] */ + FN_DU1_DG7, FN_LCDOUT15, FN_HTX0_B, + FN_SCIFB2_RTS_N_B, FN_SSI_WS9_B, + 0, 0, 0, + /* IP8_11_9 [3] */ + FN_DU1_DG6, FN_LCDOUT14, FN_HRTS0_N_B, + FN_SCIFB2_CTS_N_B, FN_SSI_SCK9_B, + 0, 0, 0, + /* IP8_8_6 [3] */ + FN_DU1_DG5, FN_LCDOUT13, FN_VI1_DATA7_B, FN_HCTS0_N_B, + FN_SCIFB2_TXD_B, FN_SSI_SDATA8_B, + 0, 0, + /* IP8_5_3 [3] */ + FN_DU1_DG4, FN_LCDOUT12, FN_VI1_DATA6_B, FN_HRX0_B, + FN_SCIFB2_RXD_B, FN_SSI_SDATA7_B, + 0, 0, + /* IP8_2_0 [3] */ + FN_DU1_DG3, FN_LCDOUT11, FN_VI1_DATA5_B, 0, FN_SSI_WS78_B, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32, + 3, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 1, 1, 3, 3) { + /* IP9_31_29 [3] */ + FN_VI0_G0, FN_SCL8, FN_STP_IVCXO27_0_C, FN_SCL4, + FN_HCTS2_N, FN_SCIFB2_CTS_N, FN_ATAWR1_N, 0, + /* IP9_28_27 [2] */ + FN_VI0_DATA3_VI0_B3, FN_SCIF3_SCK_B, FN_SCIFA3_SCK_B, 0, + /* IP9_26_25 [2] */ + FN_VI0_VSYNC_N, FN_RX5, FN_SCIFA5_RXD, FN_TS_SPSYNC0_D, + /* IP9_24_23 [2] */ + FN_VI0_HSYNC_N, FN_TX5, FN_SCIFA5_TXD, FN_TS_SDEN0_D, + /* IP9_22_21 [2] */ + FN_VI0_FIELD, FN_RX4, FN_SCIFA4_RXD, FN_TS_SCK0_D, + /* IP9_20_19 [2] */ + FN_VI0_CLKENB, FN_TX4, FN_SCIFA4_TXD, FN_TS_SDATA0_D, + /* IP9_18_17 [2] */ + FN_DU1_CDE, FN_QPOLB, FN_PWM4_B, 0, + /* IP9_16 [1] */ + FN_DU1_DISP, FN_QPOLA, + /* IP9_15_13 [3] */ + FN_DU1_EXODDF_DU1_ODDF_DISP_CDE, FN_QCPV_QDE, + FN_CAN0_RX, FN_RX3_B, FN_SDA2_B, + 0, 0, 0, + /* IP9_12 [1] */ + FN_DU1_EXVSYNC_DU1_VSYNC, FN_QSTB_QHE, + /* IP9_11 [1] */ + FN_DU1_EXHSYNC_DU1_HSYNC, FN_QSTH_QHS, + /* IP9_10_8 [3] */ + FN_DU1_DOTCLKOUT1, FN_QSTVB_QVE, FN_CAN0_TX, + FN_TX3_B, FN_SCL2_B, FN_PWM4, + 0, 0, + /* IP9_7 [1] */ + FN_DU1_DOTCLKOUT0, FN_QCLK, + /* IP9_6 [1] */ + FN_DU1_DOTCLKIN, FN_QSTVA_QVS, + /* IP9_5_3 [3] */ + FN_DU1_DB7, FN_LCDOUT23, FN_SDA3_C, + FN_SCIF3_SCK, FN_SCIFA3_SCK, + 0, 0, 0, + /* IP9_2_0 [3] */ + FN_DU1_DB6, FN_LCDOUT22, FN_SCL3_C, FN_RX3, FN_SCIFA3_RXD, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR10", 0xE6060048, 32, + 3, 2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3) { + /* IP10_31_29 [3] */ + FN_VI0_R4, FN_VI2_DATA5, FN_GLO_SCLK_B, FN_TX0_C, FN_SCL1_D, + 0, 0, 0, + /* IP10_28_27 [2] */ + FN_VI0_R3, FN_VI2_DATA4, FN_GLO_Q1_B, FN_TS_SPSYNC0_C, + /* IP10_26_25 [2] */ + FN_VI0_R2, FN_VI2_DATA3, FN_GLO_Q0_B, FN_TS_SDEN0_C, + /* IP10_24_22 [3] */ + FN_VI0_R1, FN_VI2_DATA2, FN_GLO_I1_B, FN_TS_SCK0_C, FN_ATAG1_N, + 0, 0, 0, + /* IP10_21_29 [3] */ + FN_VI0_R0, FN_VI2_DATA1, FN_GLO_I0_B, + FN_TS_SDATA0_C, FN_ATACS11_N, + 0, 0, 0, + /* IP10_18_17 [2] */ + FN_VI0_G7, FN_VI2_DATA0, FN_FMIN_D, 0, + /* IP10_16_15 [2] */ + FN_VI0_G6, FN_VI2_CLK, FN_BPFCLK_D, 0, + /* IP10_14_12 [3] */ + FN_VI0_G5, FN_VI2_FIELD, FN_STP_OPWM_0_C, FN_FMCLK_D, + FN_CAN0_TX_E, FN_HTX1_D, FN_SCIFB0_TXD_D, 0, + /* IP10_11_9 [3] */ + FN_VI0_G4, FN_VI2_CLKENB, FN_STP_ISSYNC_0_C, + FN_HTX2, FN_SCIFB2_TXD, FN_SCIFB0_SCK_D, + 0, 0, + /* IP10_8_6 [3] */ + FN_VI0_G3, FN_VI2_VSYNC_N, FN_STP_ISEN_0_C, FN_SDA3_B, + FN_HRX2, FN_SCIFB2_RXD, FN_ATACS01_N, 0, + /* IP10_5_3 [3] */ + FN_VI0_G2, FN_VI2_HSYNC_N, FN_STP_ISD_0_C, FN_SCL3_B, + FN_HSCK2, FN_SCIFB2_SCK, FN_ATARD1_N, 0, + /* IP10_2_0 [3] */ + FN_VI0_G1, FN_SDA8, FN_STP_ISCLK_0_C, FN_SDA4, + FN_HRTS2_N, FN_SCIFB2_RTS_N, FN_ATADIR1_N, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR11", 0xE606004C, 32, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 3, 3, 3, 3, 3) { + /* IP11_31_30 [2] */ + FN_ETH_CRS_DV, FN_AVB_LINK, FN_SDA2_C, 0, + /* IP11_29_28 [2] */ + FN_ETH_MDIO, FN_AVB_RX_CLK, FN_SCL2_C, 0, + /* IP11_27 [1] */ + FN_VI1_DATA7, FN_AVB_MDC, + /* IP11_26 [1] */ + FN_VI1_DATA6, FN_AVB_MAGIC, + /* IP11_25 [1] */ + FN_VI1_DATA5, FN_AVB_RX_DV, + /* IP11_24 [1] */ + FN_VI1_DATA4, FN_AVB_MDIO, + /* IP11_23 [1] */ + FN_VI1_DATA3, FN_AVB_RX_ER, + /* IP11_22 [1] */ + FN_VI1_DATA2, FN_AVB_RXD7, + /* IP11_21 [1] */ + FN_VI1_DATA1, FN_AVB_RXD6, + /* IP11_20 [1] */ + FN_VI1_DATA0, FN_AVB_RXD5, + /* IP11_19 [1] */ + FN_VI1_CLK, FN_AVB_RXD4, + /* IP11_18_17 [2] */ + FN_VI1_FIELD, FN_AVB_RXD3, FN_TS_SPSYNC0_B, 0, + /* IP11_16_15 [2] */ + FN_VI1_CLKENB, FN_AVB_RXD2, FN_TS_SDEN0_B, 0, + /* IP11_14_12 [3] */ + FN_VI1_VSYNC_N, FN_AVB_RXD1, FN_TS_SCK0_B, + FN_RX4_B, FN_SCIFA4_RXD_B, + 0, 0, 0, + /* IP11_11_9 [3] */ + FN_VI1_HSYNC_N, FN_AVB_RXD0, FN_TS_SDATA0_B, + FN_TX4_B, FN_SCIFA4_TXD_B, + 0, 0, 0, + /* IP11_8_6 [3] */ + FN_VI0_R7, FN_GLO_RFON_B, FN_RX1_C, FN_CAN0_RX_E, + FN_SDA4_B, FN_HRX1_D, FN_SCIFB0_RXD_D, 0, + /* IP11_5_3 [3] */ + FN_VI0_R6, FN_VI2_DATA7, FN_GLO_SS_B, FN_TX1_C, FN_SCL4_B, + 0, 0, 0, + /* IP11_2_0 [3] */ + FN_VI0_R5, FN_VI2_DATA6, FN_GLO_SDATA_B, FN_RX0_C, FN_SDA1_D, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR12", 0xE6060050, 32, + 2, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2) { + /* IP12_31_30 [2] */ + 0, 0, 0, 0, + /* IP12_29_27 [3] */ + FN_STP_ISCLK_0, FN_AVB_TX_EN, FN_SCIFB2_RXD_D, + FN_ADICS_SAMP_B, FN_MSIOF0_SCK_C, + 0, 0, 0, + /* IP12_26_24 [3] */ + FN_STP_IVCXO27_0, FN_AVB_TXD7, FN_SCIFB2_TXD_D, + FN_ADIDATA_B, FN_MSIOF0_SYNC_C, + 0, 0, 0, + /* IP12_23_22 [2] */ + FN_ETH_MDC, FN_AVB_TXD6, FN_IERX_C, 0, + /* IP12_21_20 [2] */ + FN_ETH_TXD0, FN_AVB_TXD5, FN_IECLK_C, 0, + /* IP12_19_18 [2] */ + FN_ETH_MAGIC, FN_AVB_TXD4, FN_IETX_C, 0, + /* IP12_17_16 [2] */ + FN_ETH_TX_EN, FN_AVB_TXD3, FN_TCLK1_B, FN_CAN_CLK_B, + /* IP12_15_13 [3] */ + FN_ETH_TXD1, FN_AVB_TXD2, FN_SCIFA3_TXD_B, + FN_CAN1_TX_C, FN_MSIOF1_TXD_E, + 0, 0, 0, + /* IP12_12_10 [3] */ + FN_ETH_REFCLK, FN_AVB_TXD1, FN_SCIFA3_RXD_B, + FN_CAN1_RX_C, FN_MSIOF1_SYNC_E, + 0, 0, 0, + /* IP12_9_7 [3] */ + FN_ETH_LINK, FN_AVB_TXD0, FN_CAN0_RX_C, + FN_SDA2_D, FN_MSIOF1_SCK_E, + 0, 0, 0, + /* IP12_6_4 [3] */ + FN_ETH_RXD1, FN_AVB_GTXREFCLK, FN_CAN0_TX_C, + FN_SCL2_D, FN_MSIOF1_RXD_E, + 0, 0, 0, + /* IP12_3_2 [2] */ + FN_ETH_RXD0, FN_AVB_PHY_INT, FN_SDA3, FN_SDA7, + /* IP12_1_0 [2] */ + FN_ETH_RX_ER, FN_AVB_CRS, FN_SCL3, FN_SCL7, } + }, + { PINMUX_CFG_REG_VAR("IPSR13", 0xE6060054, 32, + 1, 3, 1, 1, 1, 2, 1, 3, 3, 1, 1, 1, 1, 1, 1, + 3, 2, 2, 3) { + /* IP13_31 [1] */ + 0, 0, + /* IP13_30_28 [3] */ + FN_SD1_CD, FN_PWM0, FN_TPU_TO0, FN_SCL1_C, + 0, 0, 0, 0, + /* IP13_27 [1] */ + FN_SD1_DATA3, FN_IERX_B, + /* IP13_26 [1] */ + FN_SD1_DATA2, FN_IECLK_B, + /* IP13_25 [1] */ + FN_SD1_DATA1, FN_IETX_B, + /* IP13_24_23 [2] */ + FN_SD1_DATA0, FN_SPEEDIN_B, 0, 0, + /* IP13_22 [1] */ + FN_SD1_CMD, FN_REMOCON_B, + /* IP13_21_19 [3] */ + FN_SD0_WP, FN_MMC_D7_B, FN_SIM0_D_B, FN_CAN0_TX_F, + FN_SCIFA5_RXD_B, FN_RX3_C, + 0, 0, + /* IP13_18_16 [3] */ + FN_SD0_CD, FN_MMC_D6_B, FN_SIM0_RST_B, FN_CAN0_RX_F, + FN_SCIFA5_TXD_B, FN_TX3_C, + 0, 0, + /* IP13_15 [1] */ + FN_SD0_DATA3, FN_SSL_B, + /* IP13_14 [1] */ + FN_SD0_DATA2, FN_IO3_B, + /* IP13_13 [1] */ + FN_SD0_DATA1, FN_IO2_B, + /* IP13_12 [1] */ + FN_SD0_DATA0, FN_MISO_IO1_B, + /* IP13_11 [1] */ + FN_SD0_CMD, FN_MOSI_IO0_B, + /* IP13_10 [1] */ + FN_SD0_CLK, FN_SPCLK_B, + /* IP13_9_7 [3] */ + FN_STP_OPWM_0, FN_AVB_GTX_CLK, FN_PWM0_B, + FN_ADICHS2_B, FN_MSIOF0_TXD_C, + 0, 0, 0, + /* IP13_6_5 [2] */ + FN_STP_ISSYNC_0, FN_AVB_COL, FN_ADICHS1_B, FN_MSIOF0_RXD_C, + /* IP13_4_3 [2] */ + FN_STP_ISEN_0, FN_AVB_TX_CLK, FN_ADICHS0_B, FN_MSIOF0_SS2_C, + /* IP13_2_0 [3] */ + FN_STP_ISD_0, FN_AVB_TX_ER, FN_SCIFB2_SCK_C, + FN_ADICLK_B, FN_MSIOF0_SS1_C, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR14", 0xE6060058, 32, + 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 2) { + /* IP14_31_29 [3] */ + FN_MSIOF0_SS2, FN_MMC_D7, FN_ADICHS2, FN_RX0_E, + FN_VI1_VSYNC_N_C, FN_SDA7_C, FN_VI1_G5_B, 0, + /* IP14_28_26 [3] */ + FN_MSIOF0_SS1, FN_MMC_D6, FN_ADICHS1, FN_TX0_E, + FN_VI1_HSYNC_N_C, FN_SCL7_C, FN_VI1_G4_B, 0, + /* IP14_25_23 [3] */ + FN_MSIOF0_RXD, FN_ADICHS0, 0, FN_VI1_DATA0_C, FN_VI1_G3_B, + 0, 0, 0, + /* IP14_22_20 [3] */ + FN_MSIOF0_TXD, FN_ADICLK, 0, FN_VI1_FIELD_C, FN_VI1_G2_B, + 0, 0, 0, + /* IP14_19_17 [3] */ + FN_MSIOF0_SYNC, FN_TX2_C, FN_ADICS_SAMP, 0, + FN_VI1_CLKENB_C, FN_VI1_G1_B, + 0, 0, + /* IP14_16_14 [3] */ + FN_MSIOF0_SCK, FN_RX2_C, FN_ADIDATA, 0, + FN_VI1_CLK_C, FN_VI1_G0_B, + 0, 0, + /* IP14_13_11 [3] */ + FN_SD2_WP, FN_MMC_D5, FN_SDA8_C, FN_RX5_B, FN_SCIFA5_RXD_C, + 0, 0, 0, + /* IP14_10_8 [3] */ + FN_SD2_CD, FN_MMC_D4, FN_SCL8_C, FN_TX5_B, FN_SCIFA5_TXD_C, + 0, 0, 0, + /* IP14_7 [1] */ + FN_SD2_DATA3, FN_MMC_D3, + /* IP14_6 [1] */ + FN_SD2_DATA2, FN_MMC_D2, + /* IP14_5 [1] */ + FN_SD2_DATA1, FN_MMC_D1, + /* IP14_4 [1] */ + FN_SD2_DATA0, FN_MMC_D0, + /* IP14_3 [1] */ + FN_SD2_CMD, FN_MMC_CMD, + /* IP14_2 [1] */ + FN_SD2_CLK, FN_MMC_CLK, + /* IP14_1_0 [2] */ + FN_SD1_WP, FN_PWM1_B, FN_SDA1_C, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR15", 0xE606005C, 32, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2) { + /* IP15_31_30 [2] */ + 0, 0, 0, 0, + /* IP15_29_27 [3] */ + FN_HTX0, FN_SCIFB0_TXD, 0, FN_GLO_SCLK_C, + FN_CAN0_TX_B, FN_VI1_DATA5_C, + 0, 0, + /* IP15_26_24 [3] */ + FN_HRX0, FN_SCIFB0_RXD, 0, FN_GLO_Q1_C, + FN_CAN0_RX_B, FN_VI1_DATA4_C, + 0, 0, + /* IP15_23_21 [3] */ + FN_HSCK0, FN_SCIFB0_SCK, 0, FN_GLO_Q0_C, FN_CAN_CLK, + FN_TCLK2, FN_VI1_DATA3_C, 0, + /* IP15_20_18 [3] */ + FN_HRTS0_N, FN_SCIFB0_RTS_N, 0, FN_GLO_I1_C, FN_VI1_DATA2_C, + 0, 0, 0, + /* IP15_17_15 [3] */ + FN_HCTS0_N, FN_SCIFB0_CTS_N, 0, FN_GLO_I0_C, + FN_TCLK1, FN_VI1_DATA1_C, + 0, 0, + /* IP15_14_12 [3] */ + FN_GPS_MAG, FN_RX4_C, FN_SCIFA4_RXD_C, FN_PWM6, + FN_VI1_G7_B, FN_SCIFA3_SCK_C, + 0, 0, + /* IP15_11_9 [3] */ + FN_GPS_SIGN, FN_TX4_C, FN_SCIFA4_TXD_C, FN_PWM5, + FN_VI1_G6_B, FN_SCIFA3_RXD_C, + 0, 0, + /* IP15_8_6 [3] */ + FN_GPS_CLK, FN_DU1_DOTCLKIN_C, FN_AUDIO_CLKB_B, + FN_PWM5_B, FN_SCIFA3_TXD_C, + 0, 0, 0, + /* IP15_5_4 [2] */ + FN_SIM0_D, FN_IERX, FN_CAN1_RX_D, 0, + /* IP15_3_2 [2] */ + FN_SIM0_CLK, FN_IECLK, FN_CAN_CLK_C, 0, + /* IP15_1_0 [2] */ + FN_SIM0_RST, FN_IETX, FN_CAN1_TX_D, 0, } + }, + { PINMUX_CFG_REG_VAR("IPSR16", 0xE6060160, 32, + 4, 4, 4, 4, 4, 2, 2, 2, 3, 3) { + /* IP16_31_28 [4] */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* IP16_27_24 [4] */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* IP16_23_20 [4] */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* IP16_19_16 [4] */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* IP16_15_12 [4] */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* IP16_11_10 [2] */ + FN_HRTS1_N, FN_SCIFB1_RTS_N, FN_MLB_DAT, FN_CAN1_RX_B, + /* IP16_9_8 [2] */ + FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B, + /* IP16_7_6 [2] */ + FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C, + /* IP16_5_3 [3] */ + FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B, + FN_GLO_SS_C, FN_VI1_DATA7_C, + 0, 0, 0, + /* IP16_2_0 [3] */ + FN_HRX1, FN_SCIFB1_RXD, FN_VI1_R0_B, + FN_GLO_SDATA_C, FN_VI1_DATA6_C, + 0, 0, 0, } + }, + { PINMUX_CFG_REG_VAR("MOD_SEL", 0xE6060090, 32, + 1, 2, 2, 2, 3, 2, 1, 1, 1, 1, + 3, 2, 2, 2, 1, 2, 2, 2) { + /* RESEVED [1] */ + 0, 0, + /* SEL_SCIF1 [2] */ + FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3, + /* SEL_SCIFB [2] */ + FN_SEL_SCIFB_0, FN_SEL_SCIFB_1, FN_SEL_SCIFB_2, FN_SEL_SCIFB_3, + /* SEL_SCIFB2 [2] */ + FN_SEL_SCIFB2_0, FN_SEL_SCIFB2_1, + FN_SEL_SCIFB2_2, FN_SEL_SCIFB2_3, + /* SEL_SCIFB1 [3] */ + FN_SEL_SCIFB1_0, FN_SEL_SCIFB1_1, + FN_SEL_SCIFB1_2, FN_SEL_SCIFB1_3, + 0, 0, 0, 0, + /* SEL_SCIFA1 [2] */ + FN_SEL_SCIFA1_0, FN_SEL_SCIFA1_1, FN_SEL_SCIFA1_2, 0, + /* SEL_SSI9 [1] */ + FN_SEL_SSI9_0, FN_SEL_SSI9_1, + /* SEL_SCFA [1] */ + FN_SEL_SCFA_0, FN_SEL_SCFA_1, + /* SEL_QSP [1] */ + FN_SEL_QSP_0, FN_SEL_QSP_1, + /* SEL_SSI7 [1] */ + FN_SEL_SSI7_0, FN_SEL_SSI7_1, + /* SEL_HSCIF1 [3] */ + FN_SEL_HSCIF1_0, FN_SEL_HSCIF1_1, FN_SEL_HSCIF1_2, + FN_SEL_HSCIF1_3, FN_SEL_HSCIF1_4, + 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* SEL_VI1 [2] */ + FN_SEL_VI1_0, FN_SEL_VI1_1, FN_SEL_VI1_2, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* SEL_TMU [1] */ + FN_SEL_TMU1_0, FN_SEL_TMU1_1, + /* SEL_LBS [2] */ + FN_SEL_LBS_0, FN_SEL_LBS_1, FN_SEL_LBS_2, FN_SEL_LBS_3, + /* SEL_TSIF0 [2] */ + FN_SEL_TSIF0_0, FN_SEL_TSIF0_1, FN_SEL_TSIF0_2, FN_SEL_TSIF0_3, + /* SEL_SOF0 [2] */ + FN_SEL_SOF0_0, FN_SEL_SOF0_1, FN_SEL_SOF0_2, 0, } + }, + { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xE6060094, 32, + 3, 1, 1, 3, 2, 1, 1, 2, 2, + 1, 3, 2, 1, 2, 2, 2, 1, 1, 1) { + /* SEL_SCIF0 [3] */ + FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, + FN_SEL_SCIF0_3, FN_SEL_SCIF0_4, + 0, 0, 0, + /* RESEVED [1] */ + 0, 0, + /* SEL_SCIF [1] */ + FN_SEL_SCIF_0, FN_SEL_SCIF_1, + /* SEL_CAN0 [3] */ + FN_SEL_CAN0_0, FN_SEL_CAN0_1, FN_SEL_CAN0_2, FN_SEL_CAN0_3, + FN_SEL_CAN0_4, FN_SEL_CAN0_5, + 0, 0, + /* SEL_CAN1 [2] */ + FN_SEL_CAN1_0, FN_SEL_CAN1_1, FN_SEL_CAN1_2, FN_SEL_CAN1_3, + /* RESEVED [1] */ + 0, 0, + /* SEL_SCIFA2 [1] */ + FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1, + /* SEL_SCIF4 [2] */ + FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* SEL_ADG [1] */ + FN_SEL_ADG_0, FN_SEL_ADG_1, + /* SEL_FM [3] */ + FN_SEL_FM_0, FN_SEL_FM_1, FN_SEL_FM_2, + FN_SEL_FM_3, FN_SEL_FM_4, + 0, 0, 0, + /* SEL_SCIFA5 [2] */ + FN_SEL_SCIFA5_0, FN_SEL_SCIFA5_1, FN_SEL_SCIFA5_2, 0, + /* RESEVED [1] */ + 0, 0, + /* SEL_GPS [2] */ + FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, FN_SEL_GPS_3, + /* SEL_SCIFA4 [2] */ + FN_SEL_SCIFA4_0, FN_SEL_SCIFA4_1, FN_SEL_SCIFA4_2, 0, + /* SEL_SCIFA3 [2] */ + FN_SEL_SCIFA3_0, FN_SEL_SCIFA3_1, FN_SEL_SCIFA3_2, 0, + /* SEL_SIM [1] */ + FN_SEL_SIM_0, FN_SEL_SIM_1, + /* RESEVED [1] */ + 0, 0, + /* SEL_SSI8 [1] */ + FN_SEL_SSI8_0, FN_SEL_SSI8_1, } + }, + { PINMUX_CFG_REG_VAR("MOD_SEL3", 0xE6060098, 32, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 2, 2, 3, 2, 2, 2, 1) { + /* SEL_HSCIF2 [2] */ + FN_SEL_HSCIF2_0, FN_SEL_HSCIF2_1, + FN_SEL_HSCIF2_2, FN_SEL_HSCIF2_3, + /* SEL_CANCLK [2] */ + FN_SEL_CANCLK_0, FN_SEL_CANCLK_1, + FN_SEL_CANCLK_2, FN_SEL_CANCLK_3, + /* SEL_IIC8 [2] */ + FN_SEL_IIC8_0, FN_SEL_IIC8_1, FN_SEL_IIC8_2, 0, + /* SEL_IIC7 [2] */ + FN_SEL_IIC7_0, FN_SEL_IIC7_1, FN_SEL_IIC7_2, 0, + /* SEL_IIC4 [2] */ + FN_SEL_IIC4_0, FN_SEL_IIC4_1, FN_SEL_IIC4_2, 0, + /* SEL_IIC3 [2] */ + FN_SEL_IIC3_0, FN_SEL_IIC3_1, FN_SEL_IIC3_2, FN_SEL_IIC3_3, + /* SEL_SCIF3 [2] */ + FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3, + /* SEL_IEB [2] */ + FN_SEL_IEB_0, FN_SEL_IEB_1, FN_SEL_IEB_2, + /* SEL_MMC [1] */ + FN_SEL_MMC_0, FN_SEL_MMC_1, + /* SEL_SCIF5 [1] */ + FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* SEL_IIC2 [2] */ + FN_SEL_IIC2_0, FN_SEL_IIC2_1, FN_SEL_IIC2_2, FN_SEL_IIC2_3, + /* SEL_IIC1 [3] */ + FN_SEL_IIC1_0, FN_SEL_IIC1_1, FN_SEL_IIC1_2, FN_SEL_IIC1_3, + FN_SEL_IIC1_4, + 0, 0, 0, + /* SEL_IIC0 [2] */ + FN_SEL_IIC0_0, FN_SEL_IIC0_1, FN_SEL_IIC0_2, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* RESEVED [1] */ + 0, 0, } + }, + { PINMUX_CFG_REG_VAR("MOD_SEL4", 0xE606009C, 32, + 3, 2, 2, 1, 1, 1, 1, 3, 2, + 2, 3, 1, 1, 1, 2, 2, 2, 2) { + /* SEL_SOF1 [3] */ + FN_SEL_SOF1_0, FN_SEL_SOF1_1, FN_SEL_SOF1_2, FN_SEL_SOF1_3, + FN_SEL_SOF1_4, + 0, 0, 0, + /* SEL_HSCIF0 [2] */ + FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1, FN_SEL_HSCIF0_2, 0, + /* SEL_DIS [2] */ + FN_SEL_DIS_0, FN_SEL_DIS_1, FN_SEL_DIS_2, 0, + /* RESEVED [1] */ + 0, 0, + /* SEL_RAD [1] */ + FN_SEL_RAD_0, FN_SEL_RAD_1, + /* SEL_RCN [1] */ + FN_SEL_RCN_0, FN_SEL_RCN_1, + /* SEL_RSP [1] */ + FN_SEL_RSP_0, FN_SEL_RSP_1, + /* SEL_SCIF2 [3] */ + FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, + FN_SEL_SCIF2_3, FN_SEL_SCIF2_4, + 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* SEL_SOF2 [3] */ + FN_SEL_SOF2_0, FN_SEL_SOF2_1, FN_SEL_SOF2_2, + FN_SEL_SOF2_3, FN_SEL_SOF2_4, + 0, 0, 0, + /* RESEVED [1] */ + 0, 0, + /* SEL_SSI1 [1] */ + FN_SEL_SSI1_0, FN_SEL_SSI1_1, + /* SEL_SSI0 [1] */ + FN_SEL_SSI0_0, FN_SEL_SSI0_1, + /* SEL_SSP [2] */ + FN_SEL_SSP_0, FN_SEL_SSP_1, FN_SEL_SSP_2, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, + /* RESEVED [2] */ + 0, 0, 0, 0, } + }, + { }, +}; + +const struct sh_pfc_soc_info r8a7791_pinmux_info = { + .name = "r8a77910_pfc", + .unlock_reg = 0xe6060000, /* PMMR */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups, + .nr_groups = ARRAY_SIZE(pinmux_groups), + .functions = pinmux_functions, + .nr_functions = ARRAY_SIZE(pinmux_functions), + + .cfg_regs = pinmux_config_regs, + + .gpio_data = pinmux_data, + .gpio_data_size = ARRAY_SIZE(pinmux_data), +}; diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c index edf45a6940c..8ab7898d21b 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas6.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c @@ -122,6 +122,9 @@ static const struct pinctrl_pin_desc sirfsoc_pads[] = { PINCTRL_PIN(100, "ac97_dout"), PINCTRL_PIN(101, "ac97_din"), PINCTRL_PIN(102, "x_rtc_io"), + + PINCTRL_PIN(103, "x_usb1_dp"), + PINCTRL_PIN(104, "x_usb1_dn"), }; static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { @@ -139,6 +142,7 @@ static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { static const struct sirfsoc_padmux lcd_16bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask), .muxmask = lcd_16bits_sirfsoc_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = 0, }; @@ -164,6 +168,7 @@ static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = { static const struct sirfsoc_padmux lcd_18bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask), .muxmask = lcd_18bits_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4) | BIT(15), .funcval = 0, }; @@ -189,6 +194,7 @@ static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = { static const struct sirfsoc_padmux lcd_24bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask), .muxmask = lcd_24bits_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4) | BIT(15), .funcval = 0, }; @@ -214,6 +220,7 @@ static const struct sirfsoc_muxmask lcdrom_muxmask[] = { static const struct sirfsoc_padmux lcdrom_padmux = { .muxmask_counts = ARRAY_SIZE(lcdrom_muxmask), .muxmask = lcdrom_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = BIT(4), }; @@ -237,6 +244,7 @@ static const struct sirfsoc_muxmask uart0_muxmask[] = { static const struct sirfsoc_padmux uart0_padmux = { .muxmask_counts = ARRAY_SIZE(uart0_muxmask), .muxmask = uart0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(9), .funcval = BIT(9), }; @@ -284,6 +292,7 @@ static const struct sirfsoc_muxmask uart2_muxmask[] = { static const struct sirfsoc_padmux uart2_padmux = { .muxmask_counts = ARRAY_SIZE(uart2_muxmask), .muxmask = uart2_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(10), .funcval = BIT(10), }; @@ -317,6 +326,7 @@ static const struct sirfsoc_muxmask sdmmc3_muxmask[] = { static const struct sirfsoc_padmux sdmmc3_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask), .muxmask = sdmmc3_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(7), .funcval = 0, }; @@ -336,6 +346,7 @@ static const struct sirfsoc_muxmask spi0_muxmask[] = { static const struct sirfsoc_padmux spi0_padmux = { .muxmask_counts = ARRAY_SIZE(spi0_muxmask), .muxmask = spi0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(7), .funcval = BIT(7), }; @@ -352,6 +363,7 @@ static const struct sirfsoc_muxmask cko1_muxmask[] = { static const struct sirfsoc_padmux cko1_padmux = { .muxmask_counts = ARRAY_SIZE(cko1_muxmask), .muxmask = cko1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(3), .funcval = 0, }; @@ -371,6 +383,7 @@ static const struct sirfsoc_muxmask i2s_muxmask[] = { static const struct sirfsoc_padmux i2s_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_muxmask), .muxmask = i2s_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(3), .funcval = BIT(3), }; @@ -390,6 +403,7 @@ static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = { static const struct sirfsoc_padmux i2s_no_din_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask), .muxmask = i2s_no_din_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(3), .funcval = BIT(3), }; @@ -409,6 +423,7 @@ static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = { static const struct sirfsoc_padmux i2s_6chn_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask), .muxmask = i2s_6chn_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(1) | BIT(3) | BIT(9), .funcval = BIT(1) | BIT(3) | BIT(9), }; @@ -439,6 +454,7 @@ static const struct sirfsoc_muxmask spi1_muxmask[] = { static const struct sirfsoc_padmux spi1_padmux = { .muxmask_counts = ARRAY_SIZE(spi1_muxmask), .muxmask = spi1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(16), .funcval = 0, }; @@ -455,6 +471,7 @@ static const struct sirfsoc_muxmask sdmmc1_muxmask[] = { static const struct sirfsoc_padmux sdmmc1_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc1_muxmask), .muxmask = sdmmc1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5), .funcval = BIT(5), }; @@ -471,6 +488,7 @@ static const struct sirfsoc_muxmask gps_muxmask[] = { static const struct sirfsoc_padmux gps_padmux = { .muxmask_counts = ARRAY_SIZE(gps_muxmask), .muxmask = gps_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(13), .funcval = 0, }; @@ -487,6 +505,7 @@ static const struct sirfsoc_muxmask sdmmc5_muxmask[] = { static const struct sirfsoc_padmux sdmmc5_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask), .muxmask = sdmmc5_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(13), .funcval = BIT(13), }; @@ -503,6 +522,7 @@ static const struct sirfsoc_muxmask usp0_muxmask[] = { static const struct sirfsoc_padmux usp0_padmux = { .muxmask_counts = ARRAY_SIZE(usp0_muxmask), .muxmask = usp0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(1) | BIT(2) | BIT(9), .funcval = 0, }; @@ -535,6 +555,7 @@ static const struct sirfsoc_muxmask usp1_muxmask[] = { static const struct sirfsoc_padmux usp1_padmux = { .muxmask_counts = ARRAY_SIZE(usp1_muxmask), .muxmask = usp1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(16), .funcval = BIT(16), }; @@ -554,6 +575,7 @@ static const struct sirfsoc_muxmask nand_muxmask[] = { static const struct sirfsoc_padmux nand_padmux = { .muxmask_counts = ARRAY_SIZE(nand_muxmask), .muxmask = nand_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5) | BIT(19), .funcval = 0, }; @@ -570,6 +592,7 @@ static const struct sirfsoc_muxmask sdmmc0_muxmask[] = { static const struct sirfsoc_padmux sdmmc0_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc0_muxmask), .muxmask = sdmmc0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5) | BIT(19), .funcval = BIT(19), }; @@ -586,6 +609,7 @@ static const struct sirfsoc_muxmask sdmmc2_muxmask[] = { static const struct sirfsoc_padmux sdmmc2_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask), .muxmask = sdmmc2_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(11), .funcval = 0, }; @@ -602,6 +626,7 @@ static const struct sirfsoc_muxmask sdmmc2_nowp_muxmask[] = { static const struct sirfsoc_padmux sdmmc2_nowp_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc2_nowp_muxmask), .muxmask = sdmmc2_nowp_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(11), .funcval = 0, }; @@ -634,6 +659,7 @@ static const struct sirfsoc_muxmask vip_muxmask[] = { static const struct sirfsoc_padmux vip_padmux = { .muxmask_counts = ARRAY_SIZE(vip_muxmask), .muxmask = vip_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(18), .funcval = BIT(18), }; @@ -654,6 +680,7 @@ static const struct sirfsoc_muxmask vip_noupli_muxmask[] = { static const struct sirfsoc_padmux vip_noupli_padmux = { .muxmask_counts = ARRAY_SIZE(vip_noupli_muxmask), .muxmask = vip_noupli_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(15), .funcval = BIT(15), }; @@ -684,6 +711,7 @@ static const struct sirfsoc_muxmask i2c1_muxmask[] = { static const struct sirfsoc_padmux i2c1_padmux = { .muxmask_counts = ARRAY_SIZE(i2c1_muxmask), .muxmask = i2c1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(16), .funcval = 0, }; @@ -700,6 +728,7 @@ static const struct sirfsoc_muxmask pwm0_muxmask[] = { static const struct sirfsoc_padmux pwm0_padmux = { .muxmask_counts = ARRAY_SIZE(pwm0_muxmask), .muxmask = pwm0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(12), .funcval = 0, }; @@ -772,6 +801,7 @@ static const struct sirfsoc_muxmask warm_rst_muxmask[] = { static const struct sirfsoc_padmux warm_rst_padmux = { .muxmask_counts = ARRAY_SIZE(warm_rst_muxmask), .muxmask = warm_rst_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = 0, }; @@ -789,6 +819,7 @@ static const struct sirfsoc_muxmask usb0_upli_drvbus_muxmask[] = { static const struct sirfsoc_padmux usb0_upli_drvbus_padmux = { .muxmask_counts = ARRAY_SIZE(usb0_upli_drvbus_muxmask), .muxmask = usb0_upli_drvbus_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(18), .funcval = 0, }; @@ -805,12 +836,31 @@ static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = { static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = { .muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask), .muxmask = usb1_utmi_drvbus_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(11), .funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */ }; static const unsigned usb1_utmi_drvbus_pins[] = { 28 }; +static const struct sirfsoc_padmux usb1_dp_dn_padmux = { + .muxmask_counts = 0, + .ctrlreg = SIRFSOC_RSC_USB_UART_SHARE, + .funcmask = BIT(2), + .funcval = BIT(2), +}; + +static const unsigned usb1_dp_dn_pins[] = { 103, 104 }; + +static const struct sirfsoc_padmux uart1_route_io_usb1_padmux = { + .muxmask_counts = 0, + .ctrlreg = SIRFSOC_RSC_USB_UART_SHARE, + .funcmask = BIT(2), + .funcval = 0, +}; + +static const unsigned uart1_route_io_usb1_pins[] = { 103, 104 }; + static const struct sirfsoc_muxmask pulse_count_muxmask[] = { { .group = 0, @@ -859,6 +909,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins), SIRFSOC_PIN_GROUP("usb0_upli_drvbusgrp", usb0_upli_drvbus_pins), SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins), + SIRFSOC_PIN_GROUP("usb1_dp_dngrp", usb1_dp_dn_pins), + SIRFSOC_PIN_GROUP("uart1_route_io_usb1grp", uart1_route_io_usb1_pins), SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins), SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins), SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins), @@ -903,6 +955,8 @@ static const char * const sdmmc5grp[] = { "sdmmc5grp" }; static const char * const sdmmc2_nowpgrp[] = { "sdmmc2_nowpgrp" }; static const char * const usb0_upli_drvbusgrp[] = { "usb0_upli_drvbusgrp" }; static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" }; +static const char * const usb1_dp_dngrp[] = { "usb1_dp_dngrp" }; +static const char * const uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; static const char * const pulse_countgrp[] = { "pulse_countgrp" }; static const char * const i2sgrp[] = { "i2sgrp" }; static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" }; @@ -949,6 +1003,8 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", sdmmc2_nowpgrp, sdmmc2_nowp_padmux), SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux), SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb1_dp_dn", usb1_dp_dngrp, usb1_dp_dn_padmux), + SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux), SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux), SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux), diff --git a/drivers/pinctrl/sirf/pinctrl-prima2.c b/drivers/pinctrl/sirf/pinctrl-prima2.c index 1f0ad1ef5a3..050777be0f1 100644 --- a/drivers/pinctrl/sirf/pinctrl-prima2.c +++ b/drivers/pinctrl/sirf/pinctrl-prima2.c @@ -126,6 +126,9 @@ static const struct pinctrl_pin_desc sirfsoc_pads[] = { PINCTRL_PIN(112, "x_ldd[13]"), PINCTRL_PIN(113, "x_ldd[14]"), PINCTRL_PIN(114, "x_ldd[15]"), + + PINCTRL_PIN(115, "x_usb1_dp"), + PINCTRL_PIN(116, "x_usb1_dn"), }; static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { @@ -143,6 +146,7 @@ static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = { static const struct sirfsoc_padmux lcd_16bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask), .muxmask = lcd_16bits_sirfsoc_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = 0, }; @@ -168,6 +172,7 @@ static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = { static const struct sirfsoc_padmux lcd_18bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask), .muxmask = lcd_18bits_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = 0, }; @@ -193,6 +198,7 @@ static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = { static const struct sirfsoc_padmux lcd_24bits_padmux = { .muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask), .muxmask = lcd_24bits_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = 0, }; @@ -218,6 +224,7 @@ static const struct sirfsoc_muxmask lcdrom_muxmask[] = { static const struct sirfsoc_padmux lcdrom_padmux = { .muxmask_counts = ARRAY_SIZE(lcdrom_muxmask), .muxmask = lcdrom_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(4), .funcval = BIT(4), }; @@ -238,6 +245,7 @@ static const struct sirfsoc_muxmask uart0_muxmask[] = { static const struct sirfsoc_padmux uart0_padmux = { .muxmask_counts = ARRAY_SIZE(uart0_muxmask), .muxmask = uart0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(9), .funcval = BIT(9), }; @@ -282,6 +290,7 @@ static const struct sirfsoc_muxmask uart2_muxmask[] = { static const struct sirfsoc_padmux uart2_padmux = { .muxmask_counts = ARRAY_SIZE(uart2_muxmask), .muxmask = uart2_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(10), .funcval = BIT(10), }; @@ -315,6 +324,7 @@ static const struct sirfsoc_muxmask sdmmc3_muxmask[] = { static const struct sirfsoc_padmux sdmmc3_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask), .muxmask = sdmmc3_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(7), .funcval = 0, }; @@ -331,6 +341,7 @@ static const struct sirfsoc_muxmask spi0_muxmask[] = { static const struct sirfsoc_padmux spi0_padmux = { .muxmask_counts = ARRAY_SIZE(spi0_muxmask), .muxmask = spi0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(7), .funcval = BIT(7), }; @@ -361,6 +372,7 @@ static const struct sirfsoc_muxmask cko1_muxmask[] = { static const struct sirfsoc_padmux cko1_padmux = { .muxmask_counts = ARRAY_SIZE(cko1_muxmask), .muxmask = cko1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(3), .funcval = 0, }; @@ -379,6 +391,7 @@ static const struct sirfsoc_muxmask i2s_muxmask[] = { static const struct sirfsoc_padmux i2s_padmux = { .muxmask_counts = ARRAY_SIZE(i2s_muxmask), .muxmask = i2s_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(3) | BIT(9), .funcval = BIT(3), }; @@ -395,6 +408,7 @@ static const struct sirfsoc_muxmask ac97_muxmask[] = { static const struct sirfsoc_padmux ac97_padmux = { .muxmask_counts = ARRAY_SIZE(ac97_muxmask), .muxmask = ac97_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(8), .funcval = 0, }; @@ -411,6 +425,7 @@ static const struct sirfsoc_muxmask spi1_muxmask[] = { static const struct sirfsoc_padmux spi1_padmux = { .muxmask_counts = ARRAY_SIZE(spi1_muxmask), .muxmask = spi1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(8), .funcval = BIT(8), }; @@ -441,6 +456,7 @@ static const struct sirfsoc_muxmask gps_muxmask[] = { static const struct sirfsoc_padmux gps_padmux = { .muxmask_counts = ARRAY_SIZE(gps_muxmask), .muxmask = gps_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(12) | BIT(13) | BIT(14), .funcval = BIT(12), }; @@ -463,6 +479,7 @@ static const struct sirfsoc_muxmask sdmmc5_muxmask[] = { static const struct sirfsoc_padmux sdmmc5_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask), .muxmask = sdmmc5_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(13) | BIT(14), .funcval = BIT(13) | BIT(14), }; @@ -479,12 +496,27 @@ static const struct sirfsoc_muxmask usp0_muxmask[] = { static const struct sirfsoc_padmux usp0_padmux = { .muxmask_counts = ARRAY_SIZE(usp0_muxmask), .muxmask = usp0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(1) | BIT(2) | BIT(6) | BIT(9), .funcval = 0, }; static const unsigned usp0_pins[] = { 51, 52, 53, 54, 55 }; +static const struct sirfsoc_muxmask usp0_uart_nostreamctrl_muxmask[] = { + { + .group = 1, + .mask = BIT(20) | BIT(21), + }, +}; + +static const struct sirfsoc_padmux usp0_uart_nostreamctrl_padmux = { + .muxmask_counts = ARRAY_SIZE(usp0_uart_nostreamctrl_muxmask), + .muxmask = usp0_uart_nostreamctrl_muxmask, +}; + +static const unsigned usp0_uart_nostreamctrl_pins[] = { 52, 53 }; + static const struct sirfsoc_muxmask usp1_muxmask[] = { { .group = 1, @@ -495,12 +527,27 @@ static const struct sirfsoc_muxmask usp1_muxmask[] = { static const struct sirfsoc_padmux usp1_padmux = { .muxmask_counts = ARRAY_SIZE(usp1_muxmask), .muxmask = usp1_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(1) | BIT(9) | BIT(10) | BIT(11), .funcval = 0, }; static const unsigned usp1_pins[] = { 56, 57, 58, 59, 60 }; +static const struct sirfsoc_muxmask usp1_uart_nostreamctrl_muxmask[] = { + { + .group = 1, + .mask = BIT(25) | BIT(26), + }, +}; + +static const struct sirfsoc_padmux usp1_uart_nostreamctrl_padmux = { + .muxmask_counts = ARRAY_SIZE(usp1_uart_nostreamctrl_muxmask), + .muxmask = usp1_uart_nostreamctrl_muxmask, +}; + +static const unsigned usp1_uart_nostreamctrl_pins[] = { 57, 58 }; + static const struct sirfsoc_muxmask usp2_muxmask[] = { { .group = 1, @@ -514,12 +561,27 @@ static const struct sirfsoc_muxmask usp2_muxmask[] = { static const struct sirfsoc_padmux usp2_padmux = { .muxmask_counts = ARRAY_SIZE(usp2_muxmask), .muxmask = usp2_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(13) | BIT(14), .funcval = 0, }; static const unsigned usp2_pins[] = { 61, 62, 63, 64, 65 }; +static const struct sirfsoc_muxmask usp2_uart_nostreamctrl_muxmask[] = { + { + .group = 1, + .mask = BIT(30) | BIT(31), + }, +}; + +static const struct sirfsoc_padmux usp2_uart_nostreamctrl_padmux = { + .muxmask_counts = ARRAY_SIZE(usp2_uart_nostreamctrl_muxmask), + .muxmask = usp2_uart_nostreamctrl_muxmask, +}; + +static const unsigned usp2_uart_nostreamctrl_pins[] = { 62, 63 }; + static const struct sirfsoc_muxmask nand_muxmask[] = { { .group = 2, @@ -530,6 +592,7 @@ static const struct sirfsoc_muxmask nand_muxmask[] = { static const struct sirfsoc_padmux nand_padmux = { .muxmask_counts = ARRAY_SIZE(nand_muxmask), .muxmask = nand_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5), .funcval = 0, }; @@ -538,6 +601,7 @@ static const unsigned nand_pins[] = { 64, 65, 92, 93, 94 }; static const struct sirfsoc_padmux sdmmc0_padmux = { .muxmask_counts = 0, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5), .funcval = 0, }; @@ -554,6 +618,7 @@ static const struct sirfsoc_muxmask sdmmc2_muxmask[] = { static const struct sirfsoc_padmux sdmmc2_padmux = { .muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask), .muxmask = sdmmc2_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(5), .funcval = BIT(5), }; @@ -586,6 +651,7 @@ static const struct sirfsoc_muxmask vip_muxmask[] = { static const struct sirfsoc_padmux vip_padmux = { .muxmask_counts = ARRAY_SIZE(vip_muxmask), .muxmask = vip_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(0), .funcval = 0, }; @@ -635,6 +701,7 @@ static const struct sirfsoc_muxmask viprom_muxmask[] = { static const struct sirfsoc_padmux viprom_padmux = { .muxmask_counts = ARRAY_SIZE(viprom_muxmask), .muxmask = viprom_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(0), .funcval = BIT(0), }; @@ -651,6 +718,7 @@ static const struct sirfsoc_muxmask pwm0_muxmask[] = { static const struct sirfsoc_padmux pwm0_padmux = { .muxmask_counts = ARRAY_SIZE(pwm0_muxmask), .muxmask = pwm0_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(12), .funcval = 0, }; @@ -722,6 +790,7 @@ static const struct sirfsoc_muxmask usb0_utmi_drvbus_muxmask[] = { static const struct sirfsoc_padmux usb0_utmi_drvbus_padmux = { .muxmask_counts = ARRAY_SIZE(usb0_utmi_drvbus_muxmask), .muxmask = usb0_utmi_drvbus_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(6), .funcval = BIT(6), /* refer to PAD_UTMI_DRVVBUS0_ENABLE */ }; @@ -738,12 +807,31 @@ static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = { static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = { .muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask), .muxmask = usb1_utmi_drvbus_muxmask, + .ctrlreg = SIRFSOC_RSC_PIN_MUX, .funcmask = BIT(11), .funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */ }; static const unsigned usb1_utmi_drvbus_pins[] = { 59 }; +static const struct sirfsoc_padmux usb1_dp_dn_padmux = { + .muxmask_counts = 0, + .ctrlreg = SIRFSOC_RSC_USB_UART_SHARE, + .funcmask = BIT(2), + .funcval = BIT(2), +}; + +static const unsigned usb1_dp_dn_pins[] = { 115, 116 }; + +static const struct sirfsoc_padmux uart1_route_io_usb1_padmux = { + .muxmask_counts = 0, + .ctrlreg = SIRFSOC_RSC_USB_UART_SHARE, + .funcmask = BIT(2), + .funcval = 0, +}; + +static const unsigned uart1_route_io_usb1_pins[] = { 115, 116 }; + static const struct sirfsoc_muxmask pulse_count_muxmask[] = { { .group = 0, @@ -764,12 +852,19 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins), SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins), SIRFSOC_PIN_GROUP("uart0grp", uart0_pins), + SIRFSOC_PIN_GROUP("uart0_nostreamctrlgrp", uart0_nostreamctrl_pins), SIRFSOC_PIN_GROUP("uart1grp", uart1_pins), SIRFSOC_PIN_GROUP("uart2grp", uart2_pins), SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins), SIRFSOC_PIN_GROUP("usp0grp", usp0_pins), + SIRFSOC_PIN_GROUP("usp0_uart_nostreamctrl_grp", + usp0_uart_nostreamctrl_pins), SIRFSOC_PIN_GROUP("usp1grp", usp1_pins), + SIRFSOC_PIN_GROUP("usp1_uart_nostreamctrl_grp", + usp1_uart_nostreamctrl_pins), SIRFSOC_PIN_GROUP("usp2grp", usp2_pins), + SIRFSOC_PIN_GROUP("usp2_uart_nostreamctrl_grp", + usp2_uart_nostreamctrl_pins), SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins), SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins), SIRFSOC_PIN_GROUP("pwm0grp", pwm0_pins), @@ -789,6 +884,8 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = { SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins), SIRFSOC_PIN_GROUP("usb0_utmi_drvbusgrp", usb0_utmi_drvbus_pins), SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins), + SIRFSOC_PIN_GROUP("usb1_dp_dngrp", usb1_dp_dn_pins), + SIRFSOC_PIN_GROUP("uart1_route_io_usb1grp", uart1_route_io_usb1_pins), SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins), SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins), SIRFSOC_PIN_GROUP("ac97grp", ac97_pins), @@ -803,12 +900,19 @@ static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" }; static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" }; static const char * const lcdromgrp[] = { "lcdromgrp" }; static const char * const uart0grp[] = { "uart0grp" }; +static const char * const uart0_nostreamctrlgrp[] = { "uart0_nostreamctrlgrp" }; static const char * const uart1grp[] = { "uart1grp" }; static const char * const uart2grp[] = { "uart2grp" }; static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" }; static const char * const usp0grp[] = { "usp0grp" }; +static const char * const usp0_uart_nostreamctrl_grp[] = + { "usp0_uart_nostreamctrl_grp" }; static const char * const usp1grp[] = { "usp1grp" }; +static const char * const usp1_uart_nostreamctrl_grp[] = + { "usp1_uart_nostreamctrl_grp" }; static const char * const usp2grp[] = { "usp2grp" }; +static const char * const usp2_uart_nostreamctrl_grp[] = + { "usp2_uart_nostreamctrl_grp" }; static const char * const i2c0grp[] = { "i2c0grp" }; static const char * const i2c1grp[] = { "i2c1grp" }; static const char * const pwm0grp[] = { "pwm0grp" }; @@ -828,6 +932,8 @@ static const char * const sdmmc4grp[] = { "sdmmc4grp" }; static const char * const sdmmc5grp[] = { "sdmmc5grp" }; static const char * const usb0_utmi_drvbusgrp[] = { "usb0_utmi_drvbusgrp" }; static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" }; +static const char * const usb1_dp_dngrp[] = { "usb1_dp_dngrp" }; +static const char * const uart1_route_io_usb1grp[] = { "uart1_route_io_usb1grp" }; static const char * const pulse_countgrp[] = { "pulse_countgrp" }; static const char * const i2sgrp[] = { "i2sgrp" }; static const char * const ac97grp[] = { "ac97grp" }; @@ -842,12 +948,19 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux), SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux), SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux), + SIRFSOC_PMX_FUNCTION("uart0_nostreamctrl", uart0_nostreamctrlgrp, uart0_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux), SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux), SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux), + SIRFSOC_PMX_FUNCTION("usp0_uart_nostreamctrl", + usp0_uart_nostreamctrl_grp, usp0_uart_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux), + SIRFSOC_PMX_FUNCTION("usp1_uart_nostreamctrl", + usp1_uart_nostreamctrl_grp, usp1_uart_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("usp2", usp2grp, usp2_padmux), + SIRFSOC_PMX_FUNCTION("usp2_uart_nostreamctrl", + usp2_uart_nostreamctrl_grp, usp2_uart_nostreamctrl_padmux), SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux), SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux), SIRFSOC_PMX_FUNCTION("pwm0", pwm0grp, pwm0_padmux), @@ -867,6 +980,8 @@ static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = { SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux), SIRFSOC_PMX_FUNCTION("usb0_utmi_drvbus", usb0_utmi_drvbusgrp, usb0_utmi_drvbus_padmux), SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux), + SIRFSOC_PMX_FUNCTION("usb1_dp_dn", usb1_dp_dngrp, usb1_dp_dn_padmux), + SIRFSOC_PMX_FUNCTION("uart1_route_io_usb1", uart1_route_io_usb1grp, uart1_route_io_usb1_padmux), SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux), SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux), SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux), diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 26f946af793..b81e388c50d 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -166,12 +166,12 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector if (mux->funcmask && enable) { u32 func_en_val; + func_en_val = - readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); + readl(spmx->rsc_virtbase + mux->ctrlreg); func_en_val = - (func_en_val & ~mux->funcmask) | (mux-> - funcval); - writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX); + (func_en_val & ~mux->funcmask) | (mux->funcval); + writel(func_en_val, spmx->rsc_virtbase + mux->ctrlreg); } } diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.h b/drivers/pinctrl/sirf/pinctrl-sirf.h index 17cc108510b..d7f16b499ad 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.h +++ b/drivers/pinctrl/sirf/pinctrl-sirf.h @@ -9,8 +9,9 @@ #ifndef __PINMUX_SIRF_H__ #define __PINMUX_SIRF_H__ -#define SIRFSOC_NUM_PADS 622 -#define SIRFSOC_RSC_PIN_MUX 0x4 +#define SIRFSOC_NUM_PADS 622 +#define SIRFSOC_RSC_USB_UART_SHARE 0 +#define SIRFSOC_RSC_PIN_MUX 0x4 #define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) #define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90) @@ -61,6 +62,7 @@ struct sirfsoc_padmux { unsigned long muxmask_counts; const struct sirfsoc_muxmask *muxmask; /* RSC_PIN_MUX set */ + unsigned long ctrlreg; unsigned long funcmask; unsigned long funcval; }; diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c index 0a7f0bdbaa7..ff2940e9f2a 100644 --- a/drivers/pinctrl/spear/pinctrl-plgpio.c +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -735,7 +735,7 @@ static struct platform_driver plgpio_driver = { .owner = THIS_MODULE, .name = "spear-plgpio", .pm = &plgpio_dev_pm_ops, - .of_match_table = of_match_ptr(plgpio_of_match), + .of_match_table = plgpio_of_match, }, }; diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 9215ed72bec..d654f831410 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -25,7 +25,7 @@ #include <linux/interrupt.h> #include <linux/sfi.h> #include <linux/module.h> -#include <asm/mrst.h> +#include <asm/intel-mid.h> #include <asm/intel_scu_ipc.h> /* IPC defines the following message types */ @@ -579,7 +579,7 @@ static struct pci_driver ipc_driver = { static int __init intel_scu_ipc_init(void) { - platform = mrst_identify_cpu(); + platform = intel_mid_identify_cpu(); if (platform == 0) return -ENODEV; return pci_register_driver(&ipc_driver); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 03ca6c139f1..0b7efb269cf 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -23,7 +23,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define TPACPI_VERSION "0.24" +#define TPACPI_VERSION "0.25" #define TPACPI_SYSFS_VERSION 0x020700 /* @@ -88,6 +88,7 @@ #include <linux/pci_ids.h> +#include <linux/thinkpad_acpi.h> /* ThinkPad CMOS commands */ #define TP_CMOS_VOLUME_DOWN 0 @@ -8350,6 +8351,91 @@ static struct ibm_struct fan_driver_data = { .resume = fan_resume, }; +/************************************************************************* + * Mute LED subdriver + */ + + +struct tp_led_table { + acpi_string name; + int on_value; + int off_value; + int state; +}; + +static struct tp_led_table led_tables[] = { + [TPACPI_LED_MUTE] = { + .name = "SSMS", + .on_value = 1, + .off_value = 0, + }, + [TPACPI_LED_MICMUTE] = { + .name = "MMTS", + .on_value = 2, + .off_value = 0, + }, +}; + +static int mute_led_on_off(struct tp_led_table *t, bool state) +{ + acpi_handle temp; + int output; + + if (!ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) { + pr_warn("Thinkpad ACPI has no %s interface.\n", t->name); + return -EIO; + } + + if (!acpi_evalf(hkey_handle, &output, t->name, "dd", + state ? t->on_value : t->off_value)) + return -EIO; + + t->state = state; + return state; +} + +int tpacpi_led_set(int whichled, bool on) +{ + struct tp_led_table *t; + + if (whichled < 0 || whichled >= TPACPI_LED_MAX) + return -EINVAL; + + t = &led_tables[whichled]; + if (t->state < 0 || t->state == on) + return t->state; + return mute_led_on_off(t, on); +} +EXPORT_SYMBOL_GPL(tpacpi_led_set); + +static int mute_led_init(struct ibm_init_struct *iibm) +{ + acpi_handle temp; + int i; + + for (i = 0; i < TPACPI_LED_MAX; i++) { + struct tp_led_table *t = &led_tables[i]; + if (ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) + mute_led_on_off(t, false); + else + t->state = -ENODEV; + } + return 0; +} + +static void mute_led_exit(void) +{ + int i; + + for (i = 0; i < TPACPI_LED_MAX; i++) + tpacpi_led_set(i, false); +} + +static struct ibm_struct mute_led_driver_data = { + .name = "mute_led", + .exit = mute_led_exit, +}; + /**************************************************************************** **************************************************************************** * @@ -8768,6 +8854,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = fan_init, .data = &fan_driver_data, }, + { + .init = mute_led_init, + .data = &mute_led_driver_data, + }, }; static int __init set_ibm_param(const char *val, struct kernel_param *kp) diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c index d49b85164fd..4a08727fcaf 100644 --- a/drivers/ptp/ptp_ixp46x.c +++ b/drivers/ptp/ptp_ixp46x.c @@ -259,8 +259,15 @@ static struct ixp_clock ixp_clock; static int setup_interrupt(int gpio) { int irq; + int err; - gpio_line_config(gpio, IXP4XX_GPIO_IN); + err = gpio_request(gpio, "ixp4-ptp"); + if (err) + return err; + + err = gpio_direction_input(gpio); + if (err) + return err; irq = gpio_to_irq(gpio); diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 3459f60dcfd..d333f7eac10 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -141,18 +141,14 @@ struct pm800_regulators { /* Ranges are sorted in ascending order. */ static const struct regulator_linear_range buck1_volt_range[] = { - { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, - .uV_step = 12500 }, - { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50, - .max_sel = 0x54, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), + REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x54, 50000), }; /* BUCK 2~5 have same ranges. */ static const struct regulator_linear_range buck2_5_volt_range[] = { - { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, - .uV_step = 12500 }, - { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50, - .max_sel = 0x72, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), + REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x72, 50000), }; static const unsigned int ldo1_volt_table[] = { diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 70230974468..f704d83c93c 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -391,7 +391,8 @@ static int pm8607_regulator_probe(struct platform_device *pdev) else config.regmap = chip->regmap_companion; - info->regulator = regulator_register(&info->desc, &config); + info->regulator = devm_regulator_register(&pdev->dev, &info->desc, + &config); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); @@ -402,14 +403,6 @@ static int pm8607_regulator_probe(struct platform_device *pdev) return 0; } -static int pm8607_regulator_remove(struct platform_device *pdev) -{ - struct pm8607_regulator_info *info = platform_get_drvdata(pdev); - - regulator_unregister(info->regulator); - return 0; -} - static struct platform_device_id pm8607_regulator_driver_ids[] = { { .name = "88pm860x-regulator", @@ -428,7 +421,6 @@ static struct platform_driver pm8607_regulator_driver = { .owner = THIS_MODULE, }, .probe = pm8607_regulator_probe, - .remove = pm8607_regulator_remove, .id_table = pm8607_regulator_driver_ids, }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dfe58096b37..ce785f48128 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,16 +28,6 @@ config REGULATOR_DEBUG help Say yes here to enable debugging support. -config REGULATOR_DUMMY - bool "Provide a dummy regulator if regulator lookups fail" - help - If this option is enabled then when a regulator lookup fails - and the board has not specified that it has provided full - constraints the regulator core will provide an always - enabled dummy regulator, allowing consumer drivers to continue. - - A warning will be generated when this substitution is done. - config REGULATOR_FIXED_VOLTAGE tristate "Fixed voltage regulator support" help @@ -133,6 +123,14 @@ config REGULATOR_AS3711 This driver provides support for the voltage regulators on the AS3711 PMIC +config REGULATOR_AS3722 + tristate "AMS AS3722 PMIC Regulators" + depends on MFD_AS3722 + help + This driver provides support for the voltage regulators on the + AS3722 PMIC. This will enable support for all the software + controllable DCDC/LDO regulators. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X @@ -429,6 +427,14 @@ config REGULATOR_TI_ABB on TI SoCs may be unstable without enabling this as it provides device specific optimized bias to allow/optimize functionality. +config REGULATOR_STW481X_VMMC + bool "ST Microelectronics STW481X VMMC regulator" + depends on MFD_STW481X + default y if MFD_STW481X + help + This driver supports the internal VMMC regulator in the STw481x + PMIC chips. + config REGULATOR_TPS51632 tristate "TI TPS51632 Power Regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 185cce24602..01c597ea174 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,7 +3,7 @@ # -obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o @@ -18,6 +18,7 @@ obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o +obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o @@ -56,6 +57,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o +obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 881159dfcb5..f70a9bfa5ff 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -176,7 +176,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) config.driver_data = ri; config.init_data = dev_get_platdata(&pdev->dev); - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); @@ -187,21 +187,12 @@ static int aat2870_regulator_probe(struct platform_device *pdev) return 0; } -static int aat2870_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - return 0; -} - static struct platform_driver aat2870_regulator_driver = { .driver = { .name = "aat2870-regulator", .owner = THIS_MODULE, }, .probe = aat2870_regulator_probe, - .remove = aat2870_regulator_remove, }; static int __init aat2870_regulator_init(void) diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 7d5eaa874b2..77b46d0b37a 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -535,7 +535,7 @@ static int ab3100_regulator_register(struct platform_device *pdev, config.dev = &pdev->dev; config.driver_data = reg; - rdev = regulator_register(desc, &config); + rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); dev_err(&pdev->dev, @@ -616,7 +616,6 @@ static int ab3100_regulators_remove(struct platform_device *pdev) for (i = 0; i < AB3100_NUM_REGULATORS; i++) { struct ab3100_regulator *reg = &ab3100_regulators[i]; - regulator_unregister(reg->rdev); reg->rdev = NULL; } return 0; diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 02ff691cdb8..29c0faaf8eb 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -413,16 +413,12 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) &pdata->ext_regulator[i]; /* register regulator with framework */ - info->rdev = regulator_register(&info->desc, &config); + info->rdev = devm_regulator_register(&pdev->dev, &info->desc, + &config); if (IS_ERR(info->rdev)) { err = PTR_ERR(info->rdev); dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); - /* when we fail, un-register all earlier regulators */ - while (--i >= 0) { - info = &ab8500_ext_regulator_info[i]; - regulator_unregister(info->rdev); - } return err; } @@ -433,26 +429,8 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) return 0; } -static int ab8500_ext_regulator_remove(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { - struct ab8500_ext_regulator_info *info = NULL; - info = &ab8500_ext_regulator_info[i]; - - dev_vdbg(rdev_get_dev(info->rdev), - "%s-remove\n", info->desc.name); - - regulator_unregister(info->rdev); - } - - return 0; -} - static struct platform_driver ab8500_ext_regulator_driver = { .probe = ab8500_ext_regulator_probe, - .remove = ab8500_ext_regulator_remove, .driver = { .name = "ab8500-ext-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index b2b203cb6b2..48016a050d5 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -219,7 +219,6 @@ static int ad5398_probe(struct i2c_client *client, struct ad5398_chip_info *chip; const struct ad5398_current_data_format *df = (struct ad5398_current_data_format *)id->driver_data; - int ret; if (!init_data) return -EINVAL; @@ -240,33 +239,21 @@ static int ad5398_probe(struct i2c_client *client, chip->current_offset = df->current_offset; chip->current_mask = (chip->current_level - 1) << chip->current_offset; - chip->rdev = regulator_register(&ad5398_reg, &config); + chip->rdev = devm_regulator_register(&client->dev, &ad5398_reg, + &config); if (IS_ERR(chip->rdev)) { - ret = PTR_ERR(chip->rdev); dev_err(&client->dev, "failed to register %s %s\n", id->name, ad5398_reg.name); - goto err; + return PTR_ERR(chip->rdev); } i2c_set_clientdata(client, chip); dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name); return 0; - -err: - return ret; -} - -static int ad5398_remove(struct i2c_client *client) -{ - struct ad5398_chip_info *chip = i2c_get_clientdata(client); - - regulator_unregister(chip->rdev); - return 0; } static struct i2c_driver ad5398_driver = { .probe = ad5398_probe, - .remove = ad5398_remove, .driver = { .name = "ad5398", }, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 0d4a8ccbb53..c734d098082 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -200,7 +200,7 @@ static int anatop_regulator_probe(struct platform_device *pdev) config.regmap = sreg->anatop; /* register regulator */ - rdev = regulator_register(rdesc, &config); + rdev = devm_regulator_register(dev, rdesc, &config); if (IS_ERR(rdev)) { dev_err(dev, "failed to register %s\n", rdesc->name); @@ -223,7 +223,6 @@ static int anatop_regulator_remove(struct platform_device *pdev) struct anatop_regulator *sreg = rdev_get_drvdata(rdev); const char *name = sreg->name; - regulator_unregister(rdev); kfree(name); return 0; @@ -256,7 +255,7 @@ static void __exit anatop_regulator_exit(void) } module_exit(anatop_regulator_exit); -MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " - "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); +MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>"); +MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); MODULE_DESCRIPTION("ANATOP Regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 81d8681c319..4f6c2055f6b 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -226,7 +226,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev) else config.init_data = &ldo1->init_data; - ldo1->regulator = regulator_register(desc, &config); + ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -239,18 +239,8 @@ static int arizona_ldo1_probe(struct platform_device *pdev) return 0; } -static int arizona_ldo1_remove(struct platform_device *pdev) -{ - struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev); - - regulator_unregister(ldo1->regulator); - - return 0; -} - static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, - .remove = arizona_ldo1_remove, .driver = { .name = "arizona-ldo1", .owner = THIS_MODULE, diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index e87536bf0be..724706a97dc 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -225,7 +225,9 @@ static int arizona_micsupp_probe(struct platform_device *pdev) regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1, ARIZONA_CPMIC_BYPASS, 0); - micsupp->regulator = regulator_register(&arizona_micsupp, &config); + micsupp->regulator = devm_regulator_register(&pdev->dev, + &arizona_micsupp, + &config); if (IS_ERR(micsupp->regulator)) { ret = PTR_ERR(micsupp->regulator); dev_err(arizona->dev, "Failed to register mic supply: %d\n", @@ -238,18 +240,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev) return 0; } -static int arizona_micsupp_remove(struct platform_device *pdev) -{ - struct arizona_micsupp *micsupp = platform_get_drvdata(pdev); - - regulator_unregister(micsupp->regulator); - - return 0; -} - static struct platform_driver arizona_micsupp_driver = { .probe = arizona_micsupp_probe, - .remove = arizona_micsupp_remove, .driver = { .name = "arizona-micsupp", .owner = THIS_MODULE, diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 8406cd745da..c77a58478cc 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -117,26 +117,19 @@ static struct regulator_ops as3711_dldo_ops = { }; static const struct regulator_linear_range as3711_sd_ranges[] = { - { .min_uV = 612500, .max_uV = 1400000, - .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 }, - { .min_uV = 1425000, .max_uV = 2600000, - .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 }, - { .min_uV = 2650000, .max_uV = 3350000, - .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(612500, 0x1, 0x40, 12500), + REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), + REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7f, 50000), }; static const struct regulator_linear_range as3711_aldo_ranges[] = { - { .min_uV = 1200000, .max_uV = 1950000, - .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 }, - { .min_uV = 1800000, .max_uV = 3300000, - .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(1200000, 0, 0xf, 50000), + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1f, 100000), }; static const struct regulator_linear_range as3711_dldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1700000, - .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 }, - { .min_uV = 1750000, .max_uV = 3300000, - .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 0x10, 50000), + REGULATOR_LINEAR_RANGE(1750000, 0x20, 0x3f, 50000), }; #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ @@ -273,33 +266,16 @@ static int as3711_regulator_probe(struct platform_device *pdev) config.regmap = as3711->regmap; config.of_node = of_node[id]; - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); - ret = PTR_ERR(rdev); - goto eregreg; + return PTR_ERR(rdev); } reg->rdev = rdev; } platform_set_drvdata(pdev, regs); return 0; - -eregreg: - while (--id >= 0) - regulator_unregister(regs[id].rdev); - - return ret; -} - -static int as3711_regulator_remove(struct platform_device *pdev) -{ - struct as3711_regulator *regs = platform_get_drvdata(pdev); - int id; - - for (id = 0; id < AS3711_REGULATOR_NUM; ++id) - regulator_unregister(regs[id].rdev); - return 0; } static struct platform_driver as3711_regulator_driver = { @@ -308,7 +284,6 @@ static struct platform_driver as3711_regulator_driver = { .owner = THIS_MODULE, }, .probe = as3711_regulator_probe, - .remove = as3711_regulator_remove, }; static int __init as3711_regulator_init(void) diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c new file mode 100644 index 00000000000..5917fe3dc98 --- /dev/null +++ b/drivers/regulator/as3722-regulator.c @@ -0,0 +1,908 @@ +/* + * Voltage regulator support for AMS AS3722 PMIC + * + * Copyright (C) 2013 ams + * + * Author: Florian Lobmaier <florian.lobmaier@ams.com> + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* Regulator IDs */ +enum as3722_regulators_id { + AS3722_REGULATOR_ID_SD0, + AS3722_REGULATOR_ID_SD1, + AS3722_REGULATOR_ID_SD2, + AS3722_REGULATOR_ID_SD3, + AS3722_REGULATOR_ID_SD4, + AS3722_REGULATOR_ID_SD5, + AS3722_REGULATOR_ID_SD6, + AS3722_REGULATOR_ID_LDO0, + AS3722_REGULATOR_ID_LDO1, + AS3722_REGULATOR_ID_LDO2, + AS3722_REGULATOR_ID_LDO3, + AS3722_REGULATOR_ID_LDO4, + AS3722_REGULATOR_ID_LDO5, + AS3722_REGULATOR_ID_LDO6, + AS3722_REGULATOR_ID_LDO7, + AS3722_REGULATOR_ID_LDO9, + AS3722_REGULATOR_ID_LDO10, + AS3722_REGULATOR_ID_LDO11, + AS3722_REGULATOR_ID_MAX, +}; + +struct as3722_register_mapping { + u8 regulator_id; + const char *name; + const char *sname; + u8 vsel_reg; + u8 vsel_mask; + int n_voltages; + u32 enable_reg; + u8 enable_mask; + u32 control_reg; + u8 mode_mask; + u32 sleep_ctrl_reg; + u8 sleep_ctrl_mask; +}; + +struct as3722_regulator_config_data { + struct regulator_init_data *reg_init; + bool enable_tracking; + int ext_control; +}; + +struct as3722_regulators { + struct device *dev; + struct as3722 *as3722; + struct regulator_dev *rdevs[AS3722_REGULATOR_ID_MAX]; + struct regulator_desc desc[AS3722_REGULATOR_ID_MAX]; + struct as3722_regulator_config_data + reg_config_data[AS3722_REGULATOR_ID_MAX]; +}; + +static const struct as3722_register_mapping as3722_reg_lookup[] = { + { + .regulator_id = AS3722_REGULATOR_ID_SD0, + .name = "as3722-sd0", + .vsel_reg = AS3722_SD0_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(0), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD0_EXT_ENABLE_MASK, + .control_reg = AS3722_SD0_CONTROL_REG, + .mode_mask = AS3722_SD0_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD1, + .name = "as3722-sd1", + .vsel_reg = AS3722_SD1_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(1), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD1_EXT_ENABLE_MASK, + .control_reg = AS3722_SD1_CONTROL_REG, + .mode_mask = AS3722_SD1_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD2, + .name = "as3722-sd2", + .sname = "vsup-sd2", + .vsel_reg = AS3722_SD2_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(2), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD2_EXT_ENABLE_MASK, + .control_reg = AS3722_SD23_CONTROL_REG, + .mode_mask = AS3722_SD2_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD3, + .name = "as3722-sd3", + .sname = "vsup-sd3", + .vsel_reg = AS3722_SD3_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(3), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD3_EXT_ENABLE_MASK, + .control_reg = AS3722_SD23_CONTROL_REG, + .mode_mask = AS3722_SD3_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD4, + .name = "as3722-sd4", + .sname = "vsup-sd4", + .vsel_reg = AS3722_SD4_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(4), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD4_EXT_ENABLE_MASK, + .control_reg = AS3722_SD4_CONTROL_REG, + .mode_mask = AS3722_SD4_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD5, + .name = "as3722-sd5", + .sname = "vsup-sd5", + .vsel_reg = AS3722_SD5_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(5), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD5_EXT_ENABLE_MASK, + .control_reg = AS3722_SD5_CONTROL_REG, + .mode_mask = AS3722_SD5_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD6, + .name = "as3722-sd6", + .vsel_reg = AS3722_SD6_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(6), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD6_EXT_ENABLE_MASK, + .control_reg = AS3722_SD6_CONTROL_REG, + .mode_mask = AS3722_SD6_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO0, + .name = "as3722-ldo0", + .sname = "vin-ldo0", + .vsel_reg = AS3722_LDO0_VOLTAGE_REG, + .vsel_mask = AS3722_LDO0_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO0_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO0_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO0_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO1, + .name = "as3722-ldo1", + .sname = "vin-ldo1-6", + .vsel_reg = AS3722_LDO1_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO1_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO1_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO2, + .name = "as3722-ldo2", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO2_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO2_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO2_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO3, + .name = "as3722-ldo3", + .name = "vin-ldo3-4", + .vsel_reg = AS3722_LDO3_VOLTAGE_REG, + .vsel_mask = AS3722_LDO3_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO3_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO3_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO3_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO4, + .name = "as3722-ldo4", + .name = "vin-ldo3-4", + .vsel_reg = AS3722_LDO4_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO4_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO4_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO5, + .name = "as3722-ldo5", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO5_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO5_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO5_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO6, + .name = "as3722-ldo6", + .sname = "vin-ldo1-6", + .vsel_reg = AS3722_LDO6_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO6_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO6_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO7, + .name = "as3722-ldo7", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO7_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO7_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO7_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO9, + .name = "as3722-ldo9", + .sname = "vin-ldo9-10", + .vsel_reg = AS3722_LDO9_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO9_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO9_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO10, + .name = "as3722-ldo10", + .sname = "vin-ldo9-10", + .vsel_reg = AS3722_LDO10_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO10_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO10_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO11, + .name = "as3722-ldo11", + .sname = "vin-ldo11", + .vsel_reg = AS3722_LDO11_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO11_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO11_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, +}; + + +static const int as3722_ldo_current[] = { 150000, 300000 }; +static const int as3722_sd016_current[] = { 2500000, 3000000, 3500000 }; + +static int as3722_current_to_index(int min_uA, int max_uA, + const int *curr_table, int n_currents) +{ + int i; + + for (i = n_currents - 1; i >= 0; i--) { + if ((min_uA <= curr_table[i]) && (curr_table[i] <= max_uA)) + return i; + } + return -EINVAL; +} + +static int as3722_ldo_get_current_limit(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val; + int ret; + + ret = as3722_read(as3722, as3722_reg_lookup[id].vsel_reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + as3722_reg_lookup[id].vsel_reg, ret); + return ret; + } + if (val & AS3722_LDO_ILIMIT_MASK) + return 300000; + return 150000; +} + +static int as3722_ldo_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + int ret; + u32 reg = 0; + + ret = as3722_current_to_index(min_uA, max_uA, as3722_ldo_current, + ARRAY_SIZE(as3722_ldo_current)); + if (ret < 0) { + dev_err(as3722_regs->dev, + "Current range min:max = %d:%d does not support\n", + min_uA, max_uA); + return ret; + } + if (ret) + reg = AS3722_LDO_ILIMIT_BIT; + return as3722_update_bits(as3722, as3722_reg_lookup[id].vsel_reg, + AS3722_LDO_ILIMIT_MASK, reg); +} + +static struct regulator_ops as3722_ldo0_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo0_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static int as3722_ldo3_set_tracking_mode(struct as3722_regulators *as3722_reg, + int id, u8 mode) +{ + struct as3722 *as3722 = as3722_reg->as3722; + + switch (mode) { + case AS3722_LDO3_MODE_PMOS: + case AS3722_LDO3_MODE_PMOS_TRACKING: + case AS3722_LDO3_MODE_NMOS: + case AS3722_LDO3_MODE_SWITCH: + return as3722_update_bits(as3722, + as3722_reg_lookup[id].vsel_reg, + AS3722_LDO3_MODE_MASK, mode); + + default: + return -EINVAL; + } +} + +static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev) +{ + return 150000; +} + +static struct regulator_ops as3722_ldo3_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo3_get_current_limit, +}; + +static struct regulator_ops as3722_ldo3_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo3_get_current_limit, +}; + +static const struct regulator_linear_range as3722_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), + REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), +}; + +static struct regulator_ops as3722_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo_extcntrl_ops = { + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static unsigned int as3722_sd_get_mode(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val; + int ret; + + if (!as3722_reg_lookup[id].control_reg) + return -ENOTSUPP; + + ret = as3722_read(as3722, as3722_reg_lookup[id].control_reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + as3722_reg_lookup[id].control_reg, ret); + return ret; + } + + if (val & as3722_reg_lookup[id].mode_mask) + return REGULATOR_MODE_FAST; + else + return REGULATOR_MODE_NORMAL; +} + +static int as3722_sd_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + u8 id = rdev_get_id(rdev); + u8 val = 0; + int ret; + + if (!as3722_reg_lookup[id].control_reg) + return -ERANGE; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = as3722_reg_lookup[id].mode_mask; + case REGULATOR_MODE_NORMAL: /* fall down */ + break; + default: + return -EINVAL; + } + + ret = as3722_update_bits(as3722, as3722_reg_lookup[id].control_reg, + as3722_reg_lookup[id].mode_mask, val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", + as3722_reg_lookup[id].control_reg, ret); + return ret; + } + return ret; +} + +static int as3722_sd016_get_current_limit(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val, reg; + int mask; + int ret; + + switch (id) { + case AS3722_REGULATOR_ID_SD0: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD1: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD6: + reg = AS3722_OVCURRENT_DEB_REG; + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; + break; + default: + return -EINVAL; + } + ret = as3722_read(as3722, reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + reg, ret); + return ret; + } + val &= mask; + val >>= ffs(mask) - 1; + if (val == 3) + return -EINVAL; + return as3722_sd016_current[val]; +} + +static int as3722_sd016_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + int ret; + int val; + int mask; + u32 reg; + + ret = as3722_current_to_index(min_uA, max_uA, as3722_sd016_current, + ARRAY_SIZE(as3722_sd016_current)); + if (ret < 0) { + dev_err(as3722_regs->dev, + "Current range min:max = %d:%d does not support\n", + min_uA, max_uA); + return ret; + } + + switch (id) { + case AS3722_REGULATOR_ID_SD0: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD1: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD6: + reg = AS3722_OVCURRENT_DEB_REG; + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; + break; + default: + return -EINVAL; + } + val = ret & mask; + val <<= ffs(mask) - 1; + return as3722_update_bits(as3722, reg, mask, val); +} + +static const struct regulator_linear_range as3722_sd2345_ranges[] = { + REGULATOR_LINEAR_RANGE(612500, 0x01, 0x40, 12500), + REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), + REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), +}; + +static struct regulator_ops as3722_sd016_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_sd016_get_current_limit, + .set_current_limit = as3722_sd016_set_current_limit, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd016_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_sd016_get_current_limit, + .set_current_limit = as3722_sd016_set_current_limit, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static int as3722_extreg_init(struct as3722_regulators *as3722_regs, int id, + int ext_pwr_ctrl) +{ + int ret; + unsigned int val; + + if ((ext_pwr_ctrl < AS3722_EXT_CONTROL_ENABLE1) || + (ext_pwr_ctrl > AS3722_EXT_CONTROL_ENABLE3)) + return -EINVAL; + + val = ext_pwr_ctrl << (ffs(as3722_reg_lookup[id].sleep_ctrl_mask) - 1); + ret = as3722_update_bits(as3722_regs->as3722, + as3722_reg_lookup[id].sleep_ctrl_reg, + as3722_reg_lookup[id].sleep_ctrl_mask, val); + if (ret < 0) + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", + as3722_reg_lookup[id].sleep_ctrl_reg, ret); + return ret; +} + +static struct of_regulator_match as3722_regulator_matches[] = { + { .name = "sd0", }, + { .name = "sd1", }, + { .name = "sd2", }, + { .name = "sd3", }, + { .name = "sd4", }, + { .name = "sd5", }, + { .name = "sd6", }, + { .name = "ldo0", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "ldo6", }, + { .name = "ldo7", }, + { .name = "ldo9", }, + { .name = "ldo10", }, + { .name = "ldo11", }, +}; + +static int as3722_get_regulator_dt_data(struct platform_device *pdev, + struct as3722_regulators *as3722_regs) +{ + struct device_node *np; + struct as3722_regulator_config_data *reg_config; + u32 prop; + int id; + int ret; + + np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!np) { + dev_err(&pdev->dev, "Device is not having regulators node\n"); + return -ENODEV; + } + pdev->dev.of_node = np; + + ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches, + ARRAY_SIZE(as3722_regulator_matches)); + if (ret < 0) { + dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n", + ret); + return ret; + } + + for (id = 0; id < ARRAY_SIZE(as3722_regulator_matches); ++id) { + struct device_node *reg_node; + + reg_config = &as3722_regs->reg_config_data[id]; + reg_config->reg_init = as3722_regulator_matches[id].init_data; + reg_node = as3722_regulator_matches[id].of_node; + + if (!reg_config->reg_init || !reg_node) + continue; + + ret = of_property_read_u32(reg_node, "ams,ext-control", &prop); + if (!ret) { + if (prop < 3) + reg_config->ext_control = prop; + else + dev_warn(&pdev->dev, + "ext-control have invalid option: %u\n", + prop); + } + reg_config->enable_tracking = + of_property_read_bool(reg_node, "ams,enable-tracking"); + } + return 0; +} + +static int as3722_regulator_probe(struct platform_device *pdev) +{ + struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); + struct as3722_regulators *as3722_regs; + struct as3722_regulator_config_data *reg_config; + struct regulator_dev *rdev; + struct regulator_config config = { }; + struct regulator_ops *ops; + int id; + int ret; + + as3722_regs = devm_kzalloc(&pdev->dev, sizeof(*as3722_regs), + GFP_KERNEL); + if (!as3722_regs) + return -ENOMEM; + + as3722_regs->dev = &pdev->dev; + as3722_regs->as3722 = as3722; + platform_set_drvdata(pdev, as3722_regs); + + ret = as3722_get_regulator_dt_data(pdev, as3722_regs); + if (ret < 0) + return ret; + + config.dev = &pdev->dev; + config.driver_data = as3722_regs; + config.regmap = as3722->regmap; + + for (id = 0; id < AS3722_REGULATOR_ID_MAX; id++) { + reg_config = &as3722_regs->reg_config_data[id]; + + as3722_regs->desc[id].name = as3722_reg_lookup[id].name; + as3722_regs->desc[id].supply_name = as3722_reg_lookup[id].sname; + as3722_regs->desc[id].id = as3722_reg_lookup[id].regulator_id; + as3722_regs->desc[id].n_voltages = + as3722_reg_lookup[id].n_voltages; + as3722_regs->desc[id].type = REGULATOR_VOLTAGE; + as3722_regs->desc[id].owner = THIS_MODULE; + as3722_regs->desc[id].enable_reg = + as3722_reg_lookup[id].enable_reg; + as3722_regs->desc[id].enable_mask = + as3722_reg_lookup[id].enable_mask; + as3722_regs->desc[id].vsel_reg = as3722_reg_lookup[id].vsel_reg; + as3722_regs->desc[id].vsel_mask = + as3722_reg_lookup[id].vsel_mask; + switch (id) { + case AS3722_REGULATOR_ID_LDO0: + if (reg_config->ext_control) + ops = &as3722_ldo0_extcntrl_ops; + else + ops = &as3722_ldo0_ops; + as3722_regs->desc[id].min_uV = 825000; + as3722_regs->desc[id].uV_step = 25000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + break; + case AS3722_REGULATOR_ID_LDO3: + if (reg_config->ext_control) + ops = &as3722_ldo3_extcntrl_ops; + else + ops = &as3722_ldo3_ops; + as3722_regs->desc[id].min_uV = 620000; + as3722_regs->desc[id].uV_step = 20000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + if (reg_config->enable_tracking) { + ret = as3722_ldo3_set_tracking_mode(as3722_regs, + id, AS3722_LDO3_MODE_PMOS_TRACKING); + if (ret < 0) { + dev_err(&pdev->dev, + "LDO3 tracking failed: %d\n", + ret); + return ret; + } + } + break; + case AS3722_REGULATOR_ID_SD0: + case AS3722_REGULATOR_ID_SD1: + case AS3722_REGULATOR_ID_SD6: + if (reg_config->ext_control) + ops = &as3722_sd016_extcntrl_ops; + else + ops = &as3722_sd016_ops; + as3722_regs->desc[id].min_uV = 610000; + as3722_regs->desc[id].uV_step = 10000; + as3722_regs->desc[id].linear_min_sel = 1; + break; + case AS3722_REGULATOR_ID_SD2: + case AS3722_REGULATOR_ID_SD3: + case AS3722_REGULATOR_ID_SD4: + case AS3722_REGULATOR_ID_SD5: + if (reg_config->ext_control) + ops = &as3722_sd2345_extcntrl_ops; + else + ops = &as3722_sd2345_ops; + as3722_regs->desc[id].linear_ranges = + as3722_sd2345_ranges; + as3722_regs->desc[id].n_linear_ranges = + ARRAY_SIZE(as3722_sd2345_ranges); + break; + default: + if (reg_config->ext_control) + ops = &as3722_ldo_extcntrl_ops; + else + ops = &as3722_ldo_ops; + as3722_regs->desc[id].min_uV = 825000; + as3722_regs->desc[id].uV_step = 25000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges; + as3722_regs->desc[id].n_linear_ranges = + ARRAY_SIZE(as3722_ldo_ranges); + break; + } + as3722_regs->desc[id].ops = ops; + config.init_data = reg_config->reg_init; + config.of_node = as3722_regulator_matches[id].of_node; + rdev = devm_regulator_register(&pdev->dev, + &as3722_regs->desc[id], &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&pdev->dev, "regulator %d register failed %d\n", + id, ret); + return ret; + } + + as3722_regs->rdevs[id] = rdev; + if (reg_config->ext_control) { + ret = regulator_enable_regmap(rdev); + if (ret < 0) { + dev_err(&pdev->dev, + "Regulator %d enable failed: %d\n", + id, ret); + return ret; + } + ret = as3722_extreg_init(as3722_regs, id, + reg_config->ext_control); + if (ret < 0) { + dev_err(&pdev->dev, + "AS3722 ext control failed: %d", ret); + return ret; + } + } + } + return 0; +} + +static const struct of_device_id of_as3722_regulator_match[] = { + { .compatible = "ams,as3722-regulator", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_as3722_regulator_match); + +static struct platform_driver as3722_regulator_driver = { + .driver = { + .name = "as3722-regulator", + .owner = THIS_MODULE, + .of_match_table = of_as3722_regulator_match, + }, + .probe = as3722_regulator_probe, +}; + +module_platform_driver(as3722_regulator_driver); + +MODULE_ALIAS("platform:as3722-regulator"); +MODULE_DESCRIPTION("AS3722 regulator driver"); +MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a01b8b3b70c..6382f0af353 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -36,6 +36,7 @@ #include <trace/events/regulator.h> #include "dummy.h" +#include "internal.h" #define rdev_crit(rdev, fmt, ...) \ pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) @@ -52,8 +53,8 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); +static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; -static bool board_wants_dummy_regulator; static struct dentry *debugfs_root; @@ -83,22 +84,16 @@ struct regulator_enable_gpio { }; /* - * struct regulator + * struct regulator_supply_alias * - * One for each consumer device. + * Used to map lookups for a supply onto an alternative device. */ -struct regulator { - struct device *dev; +struct regulator_supply_alias { struct list_head list; - unsigned int always_on:1; - unsigned int bypass:1; - int uA_load; - int min_uV; - int max_uV; - char *supply_name; - struct device_attribute dev_attr; - struct regulator_dev *rdev; - struct dentry *debugfs; + struct device *src_dev; + const char *src_supply; + struct device *alias_dev; + const char *alias_supply; }; static int _regulator_is_enabled(struct regulator_dev *rdev); @@ -923,6 +918,36 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, return 0; } +static int machine_constraints_current(struct regulator_dev *rdev, + struct regulation_constraints *constraints) +{ + struct regulator_ops *ops = rdev->desc->ops; + int ret; + + if (!constraints->min_uA && !constraints->max_uA) + return 0; + + if (constraints->min_uA > constraints->max_uA) { + rdev_err(rdev, "Invalid current constraints\n"); + return -EINVAL; + } + + if (!ops->set_current_limit || !ops->get_current_limit) { + rdev_warn(rdev, "Operation of current configuration missing\n"); + return 0; + } + + /* Set regulator current in constraints range */ + ret = ops->set_current_limit(rdev, constraints->min_uA, + constraints->max_uA); + if (ret < 0) { + rdev_err(rdev, "Failed to set current constraint, %d\n", ret); + return ret; + } + + return 0; +} + /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -953,6 +978,10 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (ret != 0) goto out; + ret = machine_constraints_current(rdev, rdev->constraints); + if (ret != 0) + goto out; + /* do we need to setup our suspend state */ if (rdev->constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); @@ -1186,11 +1215,39 @@ overflow_err: static int _regulator_get_enable_time(struct regulator_dev *rdev) { + if (rdev->constraints && rdev->constraints->enable_time) + return rdev->constraints->enable_time; if (!rdev->desc->ops->enable_time) return rdev->desc->enable_time; return rdev->desc->ops->enable_time(rdev); } +static struct regulator_supply_alias *regulator_find_supply_alias( + struct device *dev, const char *supply) +{ + struct regulator_supply_alias *map; + + list_for_each_entry(map, ®ulator_supply_alias_list, list) + if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) + return map; + + return NULL; +} + +static void regulator_supply_alias(struct device **dev, const char **supply) +{ + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(*dev, *supply); + if (map) { + dev_dbg(*dev, "Mapping supply %s to %s,%s\n", + *supply, map->alias_supply, + dev_name(map->alias_dev)); + *dev = map->alias_dev; + *supply = map->alias_supply; + } +} + static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply, int *ret) @@ -1200,6 +1257,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, struct regulator_map *map; const char *devname = NULL; + regulator_supply_alias(&dev, &supply); + /* first do a dt based lookup */ if (dev && dev->of_node) { node = of_get_regulator(dev, supply); @@ -1243,16 +1302,16 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, - bool exclusive) + bool exclusive, bool allow_dummy) { struct regulator_dev *rdev; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); const char *devname = NULL; - int ret = 0; + int ret = -EPROBE_DEFER; if (id == NULL) { pr_err("get() with no identifier\n"); - return regulator; + return ERR_PTR(-EINVAL); } if (dev) @@ -1264,34 +1323,32 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, if (rdev) goto found; + regulator = ERR_PTR(ret); + /* * If we have return value from dev_lookup fail, we do not expect to * succeed, so, quit with appropriate error value */ - if (ret) { - regulator = ERR_PTR(ret); + if (ret && ret != -ENODEV) { goto out; } - if (board_wants_dummy_regulator) { - rdev = dummy_regulator_rdev; - goto found; - } - -#ifdef CONFIG_REGULATOR_DUMMY if (!devname) devname = "deviceless"; - /* If the board didn't flag that it was fully constrained then - * substitute in a dummy regulator so consumers can continue. + /* + * Assume that a regulator is physically present and enabled + * even if it isn't hooked up and just provide a dummy. */ - if (!has_full_constraints) { + if (has_full_constraints && allow_dummy) { pr_warn("%s supply %s not found, using dummy regulator\n", devname, id); + rdev = dummy_regulator_rdev; goto found; + } else { + dev_err(dev, "dummy supplies not allowed\n"); } -#endif mutex_unlock(®ulator_list_mutex); return regulator; @@ -1349,44 +1406,10 @@ out: */ struct regulator *regulator_get(struct device *dev, const char *id) { - return _regulator_get(dev, id, false); + return _regulator_get(dev, id, false, true); } EXPORT_SYMBOL_GPL(regulator_get); -static void devm_regulator_release(struct device *dev, void *res) -{ - regulator_put(*(struct regulator **)res); -} - -/** - * devm_regulator_get - Resource managed regulator_get() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get(). Regulators returned from this function are - * automatically regulator_put() on driver detach. See regulator_get() for more - * information. - */ -struct regulator *devm_regulator_get(struct device *dev, const char *id) -{ - struct regulator **ptr, *regulator; - - ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - regulator = regulator_get(dev, id); - if (!IS_ERR(regulator)) { - *ptr = regulator; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get); - /** * regulator_get_exclusive - obtain exclusive access to a regulator. * @dev: device for regulator "consumer" @@ -1410,7 +1433,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_get); */ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) { - return _regulator_get(dev, id, true); + return _regulator_get(dev, id, true, false); } EXPORT_SYMBOL_GPL(regulator_get_exclusive); @@ -1439,40 +1462,10 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); */ struct regulator *regulator_get_optional(struct device *dev, const char *id) { - return _regulator_get(dev, id, 0); + return _regulator_get(dev, id, false, false); } EXPORT_SYMBOL_GPL(regulator_get_optional); -/** - * devm_regulator_get_optional - Resource managed regulator_get_optional() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_optional(). Regulators returned from this - * function are automatically regulator_put() on driver detach. See - * regulator_get_optional() for more information. - */ -struct regulator *devm_regulator_get_optional(struct device *dev, - const char *id) -{ - struct regulator **ptr, *regulator; - - ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - regulator = regulator_get_optional(dev, id); - if (!IS_ERR(regulator)) { - *ptr = regulator; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_optional); - /* Locks held by regulator_put() */ static void _regulator_put(struct regulator *regulator) { @@ -1499,36 +1492,6 @@ static void _regulator_put(struct regulator *regulator) } /** - * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_exclusive(). Regulators returned from this function - * are automatically regulator_put() on driver detach. See regulator_get() for - * more information. - */ -struct regulator *devm_regulator_get_exclusive(struct device *dev, - const char *id) -{ - struct regulator **ptr, *regulator; - - ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - regulator = _regulator_get(dev, id, 1); - if (!IS_ERR(regulator)) { - *ptr = regulator; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); - -/** * regulator_put - "free" the regulator source * @regulator: regulator source * @@ -1544,34 +1507,133 @@ void regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_put); -static int devm_regulator_match(struct device *dev, void *res, void *data) +/** + * regulator_register_supply_alias - Provide device alias for supply lookup + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * All lookups for id on dev will instead be conducted for alias_id on + * alias_dev. + */ +int regulator_register_supply_alias(struct device *dev, const char *id, + struct device *alias_dev, + const char *alias_id) +{ + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(dev, id); + if (map) + return -EEXIST; + + map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); + if (!map) + return -ENOMEM; + + map->src_dev = dev; + map->src_supply = id; + map->alias_dev = alias_dev; + map->alias_supply = alias_id; + + list_add(&map->list, ®ulator_supply_alias_list); + + pr_info("Adding alias for supply %s,%s -> %s,%s\n", + id, dev_name(dev), alias_id, dev_name(alias_dev)); + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_register_supply_alias); + +/** + * regulator_unregister_supply_alias - Remove device alias + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Remove a lookup alias if one exists for id on dev. + */ +void regulator_unregister_supply_alias(struct device *dev, const char *id) { - struct regulator **r = res; - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(dev, id); + if (map) { + list_del(&map->list); + kfree(map); } - return *r == data; } +EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); /** - * devm_regulator_put - Resource managed regulator_put() - * @regulator: regulator to free + * regulator_bulk_register_supply_alias - register multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. * - * Deallocate a regulator allocated with devm_regulator_get(). Normally - * this function will not need to be called and the resource management - * code will ensure that the resource is freed. + * This helper function allows drivers to register several supply + * aliases in one operation. If any of the aliases cannot be + * registered any aliases that were registered will be removed + * before returning to the caller. */ -void devm_regulator_put(struct regulator *regulator) +int regulator_bulk_register_supply_alias(struct device *dev, const char **id, + struct device *alias_dev, + const char **alias_id, + int num_id) { - int rc; + int i; + int ret; + + for (i = 0; i < num_id; ++i) { + ret = regulator_register_supply_alias(dev, id[i], alias_dev, + alias_id[i]); + if (ret < 0) + goto err; + } + + return 0; + +err: + dev_err(dev, + "Failed to create supply alias %s,%s -> %s,%s\n", + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + + while (--i >= 0) + regulator_unregister_supply_alias(dev, id[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); + +/** + * regulator_bulk_unregister_supply_alias - unregister multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * This helper function allows drivers to unregister several supply + * aliases in one operation. + */ +void regulator_bulk_unregister_supply_alias(struct device *dev, + const char **id, + int num_id) +{ + int i; - rc = devres_release(regulator->dev, devm_regulator_release, - devm_regulator_match, regulator); - if (rc != 0) - WARN_ON(rc); + for (i = 0; i < num_id; ++i) + regulator_unregister_supply_alias(dev, id[i]); } -EXPORT_SYMBOL_GPL(devm_regulator_put); +EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); + /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ static int regulator_ena_gpio_request(struct regulator_dev *rdev, @@ -1704,11 +1766,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * together. */ trace_regulator_enable_delay(rdev_get_name(rdev)); - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); + /* + * Delay for the requested amount of time as per the guidelines in: + * + * Documentation/timers/timers-howto.txt + * + * The assumption here is that regulators will never be enabled in + * atomic context and therefore sleeping functions can be used. + */ + if (delay) { + unsigned int ms = delay / 1000; + unsigned int us = delay % 1000; + + if (ms > 0) { + /* + * For small enough values, handle super-millisecond + * delays in the usleep_range() call below. + */ + if (ms < 20) + us += ms * 1000; + else + msleep(ms); + } + + /* + * Give the scheduler some room to coalesce with any other + * wakeup sources. For delays shorter than 10 us, don't even + * bother setting up high-resolution timers and just busy- + * loop. + */ + if (us >= 10) + usleep_range(us, us + 100); + else + udelay(us); } trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -2489,6 +2579,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) ret = rdev->desc->ops->get_voltage(rdev); } else if (rdev->desc->ops->list_voltage) { ret = rdev->desc->ops->list_voltage(rdev, 0); + } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { + ret = rdev->desc->fixed_uV; } else { return -EINVAL; } @@ -2912,52 +3004,6 @@ err: } EXPORT_SYMBOL_GPL(regulator_bulk_get); -/** - * devm_regulator_bulk_get - managed get multiple regulator consumers - * - * @dev: Device to supply - * @num_consumers: Number of consumers to register - * @consumers: Configuration of consumers; clients are stored here. - * - * @return 0 on success, an errno on failure. - * - * This helper function allows drivers to get several regulator - * consumers in one operation with management, the regulators will - * automatically be freed when the device is unbound. If any of the - * regulators cannot be acquired then any regulators that were - * allocated will be freed before returning to the caller. - */ -int devm_regulator_bulk_get(struct device *dev, int num_consumers, - struct regulator_bulk_data *consumers) -{ - int i; - int ret; - - for (i = 0; i < num_consumers; i++) - consumers[i].consumer = NULL; - - for (i = 0; i < num_consumers; i++) { - consumers[i].consumer = devm_regulator_get(dev, - consumers[i].supply); - if (IS_ERR(consumers[i].consumer)) { - ret = PTR_ERR(consumers[i].consumer); - dev_err(dev, "Failed to get supply '%s': %d\n", - consumers[i].supply, ret); - consumers[i].consumer = NULL; - goto err; - } - } - - return 0; - -err: - for (i = 0; i < num_consumers && consumers[i].consumer; i++) - devm_regulator_put(consumers[i].consumer); - - return ret; -} -EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); - static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) { struct regulator_bulk_data *bulk = data; @@ -3170,7 +3216,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev) /* some attributes need specific methods to be displayed */ if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || - (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) { + (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || + (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -3614,22 +3661,6 @@ void regulator_has_full_constraints(void) EXPORT_SYMBOL_GPL(regulator_has_full_constraints); /** - * regulator_use_dummy_regulator - Provide a dummy regulator when none is found - * - * Calling this function will cause the regulator API to provide a - * dummy regulator to consumers if no physical regulator is found, - * allowing most consumers to proceed as though a regulator were - * configured. This allows systems such as those with software - * controllable regulators for the CPU core only to be brought up more - * readily. - */ -void regulator_use_dummy_regulator(void) -{ - board_wants_dummy_regulator = true; -} -EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); - -/** * rdev_get_drvdata - get rdev regulator driver data * @rdev: regulator * diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index f06854cf8cf..b431ae357fc 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -253,10 +253,8 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev, } static const struct regulator_linear_range da9034_ldo12_ranges[] = { - { .min_uV = 1700000, .max_uV = 2050000, .min_sel = 0, .max_sel = 7, - .uV_step = 50000 }, - { .min_uV = 2700000, .max_uV = 3050000, .min_sel = 8, .max_sel = 15, - .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 50000), + REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000), }; static struct regulator_ops da903x_regulator_ldo_ops = { @@ -463,7 +461,7 @@ static int da903x_regulator_probe(struct platform_device *pdev) config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = ri; - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); @@ -474,21 +472,12 @@ static int da903x_regulator_probe(struct platform_device *pdev) return 0; } -static int da903x_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - return 0; -} - static struct platform_driver da903x_regulator_driver = { .driver = { .name = "da903x-regulator", .owner = THIS_MODULE, }, .probe = da903x_regulator_probe, - .remove = da903x_regulator_remove, }; static int __init da903x_regulator_init(void) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 1e4d483f616..3adeaeffc48 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -70,6 +70,7 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; + unsigned char activate_bit; }; struct da9052_regulator { @@ -209,6 +210,36 @@ static int da9052_map_voltage(struct regulator_dev *rdev, return sel; } +static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, selector); + if (ret < 0) + return ret; + + /* Some LDOs and DCDCs are DVC controlled which requires enabling of + * the activate bit to implment the changes on the output. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, + info->activate_bit, info->activate_bit); + break; + } + + return ret; +} + static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -216,7 +247,7 @@ static struct regulator_ops da9052_dcdc_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -226,7 +257,7 @@ static struct regulator_ops da9052_ldo_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -243,14 +274,13 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ @@ -264,14 +294,13 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } static struct da9052_regulator_info da9052_regulator_info[] = { @@ -389,8 +418,9 @@ static int da9052_regulator_probe(struct platform_device *pdev) #endif } - regulator->rdev = regulator_register(®ulator->info->reg_desc, - &config); + regulator->rdev = devm_regulator_register(&pdev->dev, + ®ulator->info->reg_desc, + &config); if (IS_ERR(regulator->rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", regulator->info->reg_desc.name); @@ -402,17 +432,8 @@ static int da9052_regulator_probe(struct platform_device *pdev) return 0; } -static int da9052_regulator_remove(struct platform_device *pdev) -{ - struct da9052_regulator *regulator = platform_get_drvdata(pdev); - - regulator_unregister(regulator->rdev); - return 0; -} - static struct platform_driver da9052_regulator_driver = { .probe = da9052_regulator_probe, - .remove = da9052_regulator_remove, .driver = { .name = "da9052-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 77b53e5a231..7f340206d32 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -564,13 +564,13 @@ static int da9055_regulator_probe(struct platform_device *pdev) if (ret < 0) return ret; - regulator->rdev = regulator_register(®ulator->info->reg_desc, - &config); + regulator->rdev = devm_regulator_register(&pdev->dev, + ®ulator->info->reg_desc, + &config); if (IS_ERR(regulator->rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", regulator->info->reg_desc.name); - ret = PTR_ERR(regulator->rdev); - return ret; + return PTR_ERR(regulator->rdev); } /* Only LDO 5 and 6 has got the over current interrupt */ @@ -588,7 +588,7 @@ static int da9055_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request Regulator IRQ %d: %d\n", irq, ret); - goto err_regulator; + return ret; } } } @@ -596,24 +596,10 @@ static int da9055_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, regulator); return 0; - -err_regulator: - regulator_unregister(regulator->rdev); - return ret; -} - -static int da9055_regulator_remove(struct platform_device *pdev) -{ - struct da9055_regulator *regulator = platform_get_drvdata(pdev); - - regulator_unregister(regulator->rdev); - - return 0; } static struct platform_driver da9055_regulator_driver = { .probe = da9055_regulator_probe, - .remove = da9055_regulator_remove, .driver = { .name = "da9055-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index b9f2653e4ef..56727eb745d 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -717,7 +717,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) { struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); - struct of_regulator_match *da9063_reg_matches; + struct of_regulator_match *da9063_reg_matches = NULL; struct da9063_regulators_pdata *regl_pdata; const struct da9063_dev_model *model; struct da9063_regulators *regulators; @@ -847,13 +847,13 @@ static int da9063_regulator_probe(struct platform_device *pdev) if (da9063_reg_matches) config.of_node = da9063_reg_matches[id].of_node; config.regmap = da9063->regmap; - regl->rdev = regulator_register(®l->desc, &config); + regl->rdev = devm_regulator_register(&pdev->dev, ®l->desc, + &config); if (IS_ERR(regl->rdev)) { dev_err(&pdev->dev, "Failed to register %s regulator\n", regl->desc.name); - ret = PTR_ERR(regl->rdev); - goto err; + return PTR_ERR(regl->rdev); } id++; n++; @@ -862,9 +862,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) /* LDOs overcurrent event support */ irq = platform_get_irq_byname(pdev, "LDO_LIM"); if (irq < 0) { - ret = irq; dev_err(&pdev->dev, "Failed to get IRQ.\n"); - goto err; + return irq; } regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq); @@ -881,27 +880,15 @@ static int da9063_regulator_probe(struct platform_device *pdev) } return 0; - -err: - /* Wind back regulators registeration */ - while (--n >= 0) - regulator_unregister(regulators->regulator[n].rdev); - - return ret; } static int da9063_regulator_remove(struct platform_device *pdev) { struct da9063_regulators *regulators = platform_get_drvdata(pdev); - struct da9063_regulator *regl; free_irq(regulators->irq_ldo_lim, regulators); free_irq(regulators->irq_uvov, regulators); - for (regl = ®ulators->regulator[regulators->n_regulators - 1]; - regl >= ®ulators->regulator[0]; regl--) - regulator_unregister(regl->rdev); - return 0; } diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0fe54b3897..6f5ecbe1132 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/regmap.h> #include "da9210-regulator.h" @@ -126,7 +127,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da9210 *chip; - struct da9210_pdata *pdata = i2c->dev.platform_data; + struct device *dev = &i2c->dev; + struct da9210_pdata *pdata = dev_get_platdata(dev); struct regulator_dev *rdev = NULL; struct regulator_config config = { }; int error; @@ -147,12 +149,13 @@ static int da9210_i2c_probe(struct i2c_client *i2c, } config.dev = &i2c->dev; - if (pdata) - config.init_data = &pdata->da9210_constraints; + config.init_data = pdata ? &pdata->da9210_constraints : + of_get_regulator_init_data(dev, dev->of_node); config.driver_data = chip; config.regmap = chip->regmap; + config.of_node = dev->of_node; - rdev = regulator_register(&da9210_reg, &config); + rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config); if (IS_ERR(rdev)) { dev_err(&i2c->dev, "Failed to register DA9210 regulator\n"); return PTR_ERR(rdev); @@ -165,13 +168,6 @@ static int da9210_i2c_probe(struct i2c_client *i2c, return 0; } -static int da9210_i2c_remove(struct i2c_client *i2c) -{ - struct da9210 *chip = i2c_get_clientdata(i2c); - regulator_unregister(chip->rdev); - return 0; -} - static const struct i2c_device_id da9210_i2c_id[] = { {"da9210", 0}, {}, @@ -185,7 +181,6 @@ static struct i2c_driver da9210_regulator_driver = { .owner = THIS_MODULE, }, .probe = da9210_i2c_probe, - .remove = da9210_i2c_remove, .id_table = da9210_i2c_id, }; diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c new file mode 100644 index 00000000000..f44818b838d --- /dev/null +++ b/drivers/regulator/devres.c @@ -0,0 +1,415 @@ +/* + * devres.c -- Voltage/Current Regulator framework devres implementation. + * + * Copyright 2013 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/module.h> + +#include "internal.h" + +enum { + NORMAL_GET, + EXCLUSIVE_GET, + OPTIONAL_GET, +}; + +static void devm_regulator_release(struct device *dev, void *res) +{ + regulator_put(*(struct regulator **)res); +} + +static struct regulator *_devm_regulator_get(struct device *dev, const char *id, + int get_type) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + switch (get_type) { + case NORMAL_GET: + regulator = regulator_get(dev, id); + break; + case EXCLUSIVE_GET: + regulator = regulator_get_exclusive(dev, id); + break; + case OPTIONAL_GET: + regulator = regulator_get_optional(dev, id); + break; + default: + regulator = ERR_PTR(-EINVAL); + } + + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} + +/** + * devm_regulator_get - Resource managed regulator_get() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get(). Regulators returned from this function are + * automatically regulator_put() on driver detach. See regulator_get() for more + * information. + */ +struct regulator *devm_regulator_get(struct device *dev, const char *id) +{ + return _devm_regulator_get(dev, id, NORMAL_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get); + +/** + * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_exclusive(). Regulators returned from this function + * are automatically regulator_put() on driver detach. See regulator_get() for + * more information. + */ +struct regulator *devm_regulator_get_exclusive(struct device *dev, + const char *id) +{ + return _devm_regulator_get(dev, id, EXCLUSIVE_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); + +/** + * devm_regulator_get_optional - Resource managed regulator_get_optional() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_optional(). Regulators returned from this + * function are automatically regulator_put() on driver detach. See + * regulator_get_optional() for more information. + */ +struct regulator *devm_regulator_get_optional(struct device *dev, + const char *id) +{ + return _devm_regulator_get(dev, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get_optional); + +static int devm_regulator_match(struct device *dev, void *res, void *data) +{ + struct regulator **r = res; + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + return *r == data; +} + +/** + * devm_regulator_put - Resource managed regulator_put() + * @regulator: regulator to free + * + * Deallocate a regulator allocated with devm_regulator_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_regulator_put(struct regulator *regulator) +{ + int rc; + + rc = devres_release(regulator->dev, devm_regulator_release, + devm_regulator_match, regulator); + if (rc != 0) + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_put); + +/** + * devm_regulator_bulk_get - managed get multiple regulator consumers + * + * @dev: Device to supply + * @num_consumers: Number of consumers to register + * @consumers: Configuration of consumers; clients are stored here. + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get several regulator + * consumers in one operation with management, the regulators will + * automatically be freed when the device is unbound. If any of the + * regulators cannot be acquired then any regulators that were + * allocated will be freed before returning to the caller. + */ +int devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) + consumers[i].consumer = NULL; + + for (i = 0; i < num_consumers; i++) { + consumers[i].consumer = devm_regulator_get(dev, + consumers[i].supply); + if (IS_ERR(consumers[i].consumer)) { + ret = PTR_ERR(consumers[i].consumer); + dev_err(dev, "Failed to get supply '%s': %d\n", + consumers[i].supply, ret); + consumers[i].consumer = NULL; + goto err; + } + } + + return 0; + +err: + for (i = 0; i < num_consumers && consumers[i].consumer; i++) + devm_regulator_put(consumers[i].consumer); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); + +static void devm_rdev_release(struct device *dev, void *res) +{ + regulator_unregister(*(struct regulator_dev **)res); +} + +/** + * devm_regulator_register - Resource managed regulator_register() + * @regulator_desc: regulator to register + * @config: runtime configuration for regulator + * + * Called by regulator drivers to register a regulator. Returns a + * valid pointer to struct regulator_dev on success or an ERR_PTR() on + * error. The regulator will automatically be released when the device + * is unbound. + */ +struct regulator_dev *devm_regulator_register(struct device *dev, + const struct regulator_desc *regulator_desc, + const struct regulator_config *config) +{ + struct regulator_dev **ptr, *rdev; + + ptr = devres_alloc(devm_rdev_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + rdev = regulator_register(regulator_desc, config); + if (!IS_ERR(rdev)) { + *ptr = rdev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return rdev; +} +EXPORT_SYMBOL_GPL(devm_regulator_register); + +static int devm_rdev_match(struct device *dev, void *res, void *data) +{ + struct regulator_dev **r = res; + if (!r || !*r) { + WARN_ON(!r || !*r); + return 0; + } + return *r == data; +} + +/** + * devm_regulator_unregister - Resource managed regulator_unregister() + * @regulator: regulator to free + * + * Unregister a regulator registered with devm_regulator_register(). + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev) +{ + int rc; + + rc = devres_release(dev, devm_rdev_release, devm_rdev_match, rdev); + if (rc != 0) + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister); + +struct regulator_supply_alias_match { + struct device *dev; + const char *id; +}; + +static int devm_regulator_match_supply_alias(struct device *dev, void *res, + void *data) +{ + struct regulator_supply_alias_match *match = res; + struct regulator_supply_alias_match *target = data; + + return match->dev == target->dev && strcmp(match->id, target->id) == 0; +} + +static void devm_regulator_destroy_supply_alias(struct device *dev, void *res) +{ + struct regulator_supply_alias_match *match = res; + + regulator_unregister_supply_alias(match->dev, match->id); +} + +/** + * devm_regulator_register_supply_alias - Resource managed + * regulator_register_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * The supply alias will automatically be unregistered when the source + * device is unbound. + */ +int devm_regulator_register_supply_alias(struct device *dev, const char *id, + struct device *alias_dev, + const char *alias_id) +{ + struct regulator_supply_alias_match *match; + int ret; + + match = devres_alloc(devm_regulator_destroy_supply_alias, + sizeof(struct regulator_supply_alias_match), + GFP_KERNEL); + if (!match) + return -ENOMEM; + + match->dev = dev; + match->id = id; + + ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id); + if (ret < 0) { + devres_free(match); + return ret; + } + + devres_add(dev, match); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); + +/** + * devm_regulator_unregister_supply_alias - Resource managed + * regulator_unregister_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Unregister an alias registered with + * devm_regulator_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) +{ + struct regulator_supply_alias_match match; + int rc; + + match.dev = dev; + match.id = id; + + rc = devres_release(dev, devm_regulator_destroy_supply_alias, + devm_regulator_match_supply_alias, &match); + if (rc != 0) + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias); + +/** + * devm_regulator_bulk_register_supply_alias - Managed register + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation, the aliases will be automatically + * unregisters when the source device is unbound. If any of the + * aliases cannot be registered any aliases that were registered + * will be removed before returning to the caller. + */ +int devm_regulator_bulk_register_supply_alias(struct device *dev, + const char **id, + struct device *alias_dev, + const char **alias_id, + int num_id) +{ + int i; + int ret; + + for (i = 0; i < num_id; ++i) { + ret = devm_regulator_register_supply_alias(dev, id[i], + alias_dev, + alias_id[i]); + if (ret < 0) + goto err; + } + + return 0; + +err: + dev_err(dev, + "Failed to create supply alias %s,%s -> %s,%s\n", + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + + while (--i >= 0) + devm_regulator_unregister_supply_alias(dev, id[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); + +/** + * devm_regulator_bulk_unregister_supply_alias - Managed unregister + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * Unregister aliases registered with + * devm_regulator_bulk_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_bulk_unregister_supply_alias(struct device *dev, + const char **id, + int num_id) +{ + int i; + + for (i = 0; i < num_id; ++i) + devm_regulator_unregister_supply_alias(dev, id[i]); +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 70b7220c587..7ca3d9e3b0f 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -218,9 +218,8 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->vsel_mask = VSEL_NSEL_MASK; rdesc->owner = THIS_MODULE; - di->rdev = regulator_register(&di->desc, config); + di->rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(di->rdev); - } static struct regmap_config fan53555_regmap_config = { @@ -291,14 +290,6 @@ static int fan53555_regulator_probe(struct i2c_client *client, } -static int fan53555_regulator_remove(struct i2c_client *client) -{ - struct fan53555_device_info *di = i2c_get_clientdata(client); - - regulator_unregister(di->rdev); - return 0; -} - static const struct i2c_device_id fan53555_id[] = { {"fan53555", -1}, { }, @@ -309,7 +300,6 @@ static struct i2c_driver fan53555_regulator_driver = { .name = "fan53555-regulator", }, .probe = fan53555_regulator_probe, - .remove = fan53555_regulator_remove, .id_table = fan53555_id, }; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 7610920014d..5ea64b94341 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -34,7 +34,6 @@ struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; - int microvolts; }; @@ -108,30 +107,7 @@ of_get_fixed_voltage_config(struct device *dev) return config; } -static int fixed_voltage_get_voltage(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (data->microvolts) - return data->microvolts; - else - return -EINVAL; -} - -static int fixed_voltage_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (selector != 0) - return -EINVAL; - - return data->microvolts; -} - static struct regulator_ops fixed_voltage_ops = { - .get_voltage = fixed_voltage_get_voltage, - .list_voltage = fixed_voltage_list_voltage, }; static int reg_fixed_voltage_probe(struct platform_device *pdev) @@ -186,23 +162,21 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) if (config->microvolts) drvdata->desc.n_voltages = 1; - drvdata->microvolts = config->microvolts; + drvdata->desc.fixed_uV = config->microvolts; if (config->gpio >= 0) cfg.ena_gpio = config->gpio; cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { - if (config->enable_high) { + if (config->enable_high) cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - } else { + else cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - } } else { - if (config->enable_high) { + if (config->enable_high) cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - } else { + else cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - } } if (config->gpio_is_open_drain) cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; @@ -222,7 +196,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, - drvdata->microvolts); + drvdata->desc.fixed_uV); return 0; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 98a98ffa7fe..04406a918c0 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -283,7 +283,6 @@ static int gpio_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No regulator type set\n"); ret = -EINVAL; goto err_memgpio; - break; } drvdata->nr_gpios = config->nr_gpios; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 6e30df14714..e221a271ba5 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -284,9 +284,13 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, } for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + int linear_max_uV; + range = &rdev->desc->linear_ranges[i]; + linear_max_uV = range->min_uV + + (range->max_sel - range->min_sel) * range->uV_step; - if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) + if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) continue; if (min_uV <= range->min_uV) diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h new file mode 100644 index 00000000000..84bbda10c39 --- /dev/null +++ b/drivers/regulator/internal.h @@ -0,0 +1,38 @@ +/* + * internal.h -- Voltage/Current Regulator framework internal code + * + * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * Copyright 2008 SlimLogic Ltd. + * + * Author: Liam Girdwood <lrg@slimlogic.co.uk> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __REGULATOR_INTERNAL_H +#define __REGULATOR_INTERNAL_H + +/* + * struct regulator + * + * One for each consumer device. + */ +struct regulator { + struct device *dev; + struct list_head list; + unsigned int always_on:1; + unsigned int bypass:1; + int uA_load; + int min_uV; + int max_uV; + char *supply_name; + struct device_attribute dev_attr; + struct regulator_dev *rdev; + struct dentry *debugfs; +}; + +#endif diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 88c1a3acf56..6e5da95fa02 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -112,7 +112,7 @@ static int isl6271a_probe(struct i2c_client *i2c, struct regulator_config config = { }; struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct isl_pmic *pmic; - int err, i; + int i; if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; @@ -133,32 +133,17 @@ static int isl6271a_probe(struct i2c_client *i2c, config.init_data = NULL; config.driver_data = pmic; - pmic->rdev[i] = regulator_register(&isl_rd[i], &config); + pmic->rdev[i] = devm_regulator_register(&i2c->dev, &isl_rd[i], + &config); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); - err = PTR_ERR(pmic->rdev[i]); - goto error; + return PTR_ERR(pmic->rdev[i]); } } i2c_set_clientdata(i2c, pmic); return 0; - -error: - while (--i >= 0) - regulator_unregister(pmic->rdev[i]); - return err; -} - -static int isl6271a_remove(struct i2c_client *i2c) -{ - struct isl_pmic *pmic = i2c_get_clientdata(i2c); - int i; - - for (i = 0; i < 3; i++) - regulator_unregister(pmic->rdev[i]); - return 0; } static const struct i2c_device_id isl6271a_id[] = { @@ -174,7 +159,6 @@ static struct i2c_driver isl6271a_i2c_driver = { .owner = THIS_MODULE, }, .probe = isl6271a_probe, - .remove = isl6271a_remove, .id_table = isl6271a_id, }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 5a4604ee5ea..947c05ffe0a 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -474,8 +474,8 @@ static int lp3971_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id lp3971_i2c_id[] = { - { "lp3971", 0 }, - { } + { "lp3971", 0 }, + { } }; MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 2b84b727a3c..2e4734ff79f 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -785,7 +785,7 @@ static int lp872x_regulator_register(struct lp872x *lp) struct regulator_desc *desc; struct regulator_config cfg = { }; struct regulator_dev *rdev; - int i, ret; + int i; for (i = 0; i < lp->num_regulators; i++) { desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : @@ -796,34 +796,16 @@ static int lp872x_regulator_register(struct lp872x *lp) cfg.driver_data = lp; cfg.regmap = lp->regmap; - rdev = regulator_register(desc, &cfg); + rdev = devm_regulator_register(lp->dev, desc, &cfg); if (IS_ERR(rdev)) { dev_err(lp->dev, "regulator register err"); - ret = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } *(lp->regulators + i) = rdev; } return 0; -err: - while (--i >= 0) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } - return ret; -} - -static void lp872x_regulator_unregister(struct lp872x *lp) -{ - struct regulator_dev *rdev; - int i; - - for (i = 0; i < lp->num_regulators; i++) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } } static const struct regmap_config lp872x_regmap_config = { @@ -979,14 +961,6 @@ err_dev: return ret; } -static int lp872x_remove(struct i2c_client *cl) -{ - struct lp872x *lp = i2c_get_clientdata(cl); - - lp872x_regulator_unregister(lp); - return 0; -} - static const struct of_device_id lp872x_dt_ids[] = { { .compatible = "ti,lp8720", }, { .compatible = "ti,lp8725", }, @@ -1008,7 +982,6 @@ static struct i2c_driver lp872x_driver = { .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, - .remove = lp872x_remove, .id_table = lp872x_ids, }; diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index 0b015f2a7fd..948afc249e2 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -515,7 +515,7 @@ static int lp8788_buck_probe(struct platform_device *pdev) cfg.driver_data = buck; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_buck_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_buck_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", @@ -529,18 +529,8 @@ static int lp8788_buck_probe(struct platform_device *pdev) return 0; } -static int lp8788_buck_remove(struct platform_device *pdev) -{ - struct lp8788_buck *buck = platform_get_drvdata(pdev); - - regulator_unregister(buck->regulator); - - return 0; -} - static struct platform_driver lp8788_buck_driver = { .probe = lp8788_buck_probe, - .remove = lp8788_buck_remove, .driver = { .name = LP8788_DEV_BUCK, .owner = THIS_MODULE, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 0527d87c6dd..b9a29a29933 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -543,7 +543,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev) cfg.driver_data = ldo; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_dldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n", @@ -557,18 +557,8 @@ static int lp8788_dldo_probe(struct platform_device *pdev) return 0; } -static int lp8788_dldo_remove(struct platform_device *pdev) -{ - struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver lp8788_dldo_driver = { .probe = lp8788_dldo_probe, - .remove = lp8788_dldo_remove, .driver = { .name = LP8788_DEV_DLDO, .owner = THIS_MODULE, @@ -603,7 +593,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev) cfg.driver_data = ldo; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_aldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n", @@ -617,18 +607,8 @@ static int lp8788_aldo_probe(struct platform_device *pdev) return 0; } -static int lp8788_aldo_remove(struct platform_device *pdev) -{ - struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver lp8788_aldo_driver = { .probe = lp8788_aldo_probe, - .remove = lp8788_aldo_remove, .driver = { .name = LP8788_DEV_ALDO, .owner = THIS_MODULE, diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 3a599ee0a45..e242dd316d3 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -166,7 +166,7 @@ static int max1586_pmic_probe(struct i2c_client *client, struct max1586_platform_data *pdata = dev_get_platdata(&client->dev); struct regulator_config config = { }; struct max1586_data *max1586; - int i, id, ret = -ENOMEM; + int i, id; max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), @@ -193,7 +193,7 @@ static int max1586_pmic_probe(struct i2c_client *client, continue; if (id < MAX1586_V3 || id > MAX1586_V6) { dev_err(&client->dev, "invalid regulator id %d\n", id); - goto err; + return -EINVAL; } if (id == MAX1586_V3) { @@ -207,33 +207,18 @@ static int max1586_pmic_probe(struct i2c_client *client, config.init_data = pdata->subdevs[i].platform_data; config.driver_data = max1586; - rdev[i] = regulator_register(&max1586_reg[id], &config); + rdev[i] = devm_regulator_register(&client->dev, + &max1586_reg[id], &config); if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", max1586_reg[id].name); - goto err; + return PTR_ERR(rdev[i]); } } i2c_set_clientdata(client, max1586); dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); return 0; - -err: - while (--i >= 0) - regulator_unregister(rdev[i]); - return ret; -} - -static int max1586_pmic_remove(struct i2c_client *client) -{ - struct max1586_data *max1586 = i2c_get_clientdata(client); - int i; - - for (i = 0; i <= MAX1586_V6; i++) - regulator_unregister(max1586->rdev[i]); - return 0; } static const struct i2c_device_id max1586_id[] = { @@ -244,7 +229,6 @@ MODULE_DEVICE_TABLE(i2c, max1586_id); static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, - .remove = max1586_pmic_remove, .driver = { .name = "max1586", .owner = THIS_MODULE, diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index f563057e569..ae001ccf26f 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -478,32 +478,16 @@ static int max77686_pmic_probe(struct platform_device *pdev) config.of_node = pdata->regulators[i].of_node; max77686->opmode[i] = regulators[i].enable_mask; - max77686->rdev[i] = regulator_register(®ulators[i], &config); + max77686->rdev[i] = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); if (IS_ERR(max77686->rdev[i])) { - ret = PTR_ERR(max77686->rdev[i]); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - max77686->rdev[i] = NULL; - goto err; + return PTR_ERR(max77686->rdev[i]); } } return 0; -err: - while (--i >= 0) - regulator_unregister(max77686->rdev[i]); - return ret; -} - -static int max77686_pmic_remove(struct platform_device *pdev) -{ - struct max77686_data *max77686 = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < MAX77686_REGULATORS; i++) - regulator_unregister(max77686->rdev[i]); - - return 0; } static const struct platform_device_id max77686_pmic_id[] = { @@ -518,7 +502,6 @@ static struct platform_driver max77686_pmic_driver = { .owner = THIS_MODULE, }, .probe = max77686_pmic_probe, - .remove = max77686_pmic_remove, .id_table = max77686_pmic_id, }; diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index ce4b96c15eb..feb20bf4cca 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -230,7 +230,7 @@ static int max77693_pmic_probe(struct platform_device *pdev) struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max77693_pmic_dev *max77693_pmic; struct max77693_regulator_data *rdata = NULL; - int num_rdata, i, ret; + int num_rdata, i; struct regulator_config config; num_rdata = max77693_pmic_init_rdata(&pdev->dev, &rdata); @@ -266,36 +266,16 @@ static int max77693_pmic_probe(struct platform_device *pdev) config.init_data = rdata[i].initdata; config.of_node = rdata[i].of_node; - max77693_pmic->rdev[i] = regulator_register(®ulators[id], - &config); + max77693_pmic->rdev[i] = devm_regulator_register(&pdev->dev, + ®ulators[id], &config); if (IS_ERR(max77693_pmic->rdev[i])) { - ret = PTR_ERR(max77693_pmic->rdev[i]); dev_err(max77693_pmic->dev, "Failed to initialize regulator-%d\n", id); - max77693_pmic->rdev[i] = NULL; - goto err; + return PTR_ERR(max77693_pmic->rdev[i]); } } return 0; - err: - while (--i >= 0) - regulator_unregister(max77693_pmic->rdev[i]); - - return ret; -} - -static int max77693_pmic_remove(struct platform_device *pdev) -{ - struct max77693_pmic_dev *max77693_pmic = platform_get_drvdata(pdev); - struct regulator_dev **rdev = max77693_pmic->rdev; - int i; - - for (i = 0; i < max77693_pmic->num_regulators; i++) - if (rdev[i]) - regulator_unregister(rdev[i]); - - return 0; } static const struct platform_device_id max77693_pmic_id[] = { @@ -311,7 +291,6 @@ static struct platform_driver max77693_pmic_driver = { .owner = THIS_MODULE, }, .probe = max77693_pmic_probe, - .remove = max77693_pmic_remove, .id_table = max77693_pmic_id, }; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 19c6f08eafd..7f049c92ee5 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -234,7 +234,8 @@ static int max8649_regulator_probe(struct i2c_client *client, config.driver_data = info; config.regmap = info->regmap; - info->regulator = regulator_register(&dcdc_desc, &config); + info->regulator = devm_regulator_register(&client->dev, &dcdc_desc, + &config); if (IS_ERR(info->regulator)) { dev_err(info->dev, "failed to register regulator %s\n", dcdc_desc.name); @@ -244,16 +245,6 @@ static int max8649_regulator_probe(struct i2c_client *client, return 0; } -static int max8649_regulator_remove(struct i2c_client *client) -{ - struct max8649_regulator_info *info = i2c_get_clientdata(client); - - if (info) - regulator_unregister(info->regulator); - - return 0; -} - static const struct i2c_device_id max8649_id[] = { { "max8649", 0 }, { } @@ -262,7 +253,6 @@ MODULE_DEVICE_TABLE(i2c, max8649_id); static struct i2c_driver max8649_driver = { .probe = max8649_regulator_probe, - .remove = max8649_regulator_remove, .driver = { .name = "max8649", }, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 144bcacd734..8d94d3d7f97 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -439,7 +439,7 @@ static int max8660_probe(struct i2c_client *client, for (i = 0; i < pdata->num_subdevs; i++) { if (!pdata->subdevs[i].platform_data) - goto err_out; + return ret; boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; @@ -465,7 +465,7 @@ static int max8660_probe(struct i2c_client *client, case MAX8660_V7: if (type == MAX8661) { dev_err(dev, "Regulator not on this chip!\n"); - goto err_out; + return -EINVAL; } if (boot_on) @@ -475,7 +475,7 @@ static int max8660_probe(struct i2c_client *client, default: dev_err(dev, "invalid regulator %s\n", pdata->subdevs[i].name); - goto err_out; + return ret; } } @@ -489,33 +489,18 @@ static int max8660_probe(struct i2c_client *client, config.of_node = of_node[i]; config.driver_data = max8660; - rdev[i] = regulator_register(&max8660_reg[id], &config); + rdev[i] = devm_regulator_register(&client->dev, + &max8660_reg[id], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); - dev_err(dev, "failed to register %s\n", + dev_err(&client->dev, "failed to register %s\n", max8660_reg[id].name); - goto err_unregister; + return PTR_ERR(rdev[i]); } } i2c_set_clientdata(client, max8660); return 0; - -err_unregister: - while (--i >= 0) - regulator_unregister(rdev[i]); -err_out: - return ret; -} - -static int max8660_remove(struct i2c_client *client) -{ - struct max8660 *max8660 = i2c_get_clientdata(client); - int i; - - for (i = 0; i < MAX8660_V_END; i++) - regulator_unregister(max8660->rdev[i]); - return 0; } static const struct i2c_device_id max8660_id[] = { @@ -527,7 +512,6 @@ MODULE_DEVICE_TABLE(i2c, max8660_id); static struct i2c_driver max8660_driver = { .probe = max8660_probe, - .remove = max8660_remove, .driver = { .name = "max8660", .owner = THIS_MODULE, diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index 4568c15fa78..0c5fe6c6ac2 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -350,33 +350,17 @@ static int max8907_regulator_probe(struct platform_device *pdev) pmic->desc[i].ops = &max8907_out5v_hwctl_ops; } - pmic->rdev[i] = regulator_register(&pmic->desc[i], &config); + pmic->rdev[i] = devm_regulator_register(&pdev->dev, + &pmic->desc[i], &config); if (IS_ERR(pmic->rdev[i])) { dev_err(&pdev->dev, "failed to register %s regulator\n", pmic->desc[i].name); - ret = PTR_ERR(pmic->rdev[i]); - goto err_unregister_regulator; + return PTR_ERR(pmic->rdev[i]); } } return 0; - -err_unregister_regulator: - while (--i >= 0) - regulator_unregister(pmic->rdev[i]); - return ret; -} - -static int max8907_regulator_remove(struct platform_device *pdev) -{ - struct max8907_regulator *pmic = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < MAX8907_NUM_REGULATORS; i++) - regulator_unregister(pmic->rdev[i]); - - return 0; } static struct platform_driver max8907_regulator_driver = { @@ -385,7 +369,6 @@ static struct platform_driver max8907_regulator_driver = { .owner = THIS_MODULE, }, .probe = max8907_regulator_probe, - .remove = max8907_regulator_remove, }; static int __init max8907_regulator_init(void) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index d80b5fa758a..759510789e7 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -312,7 +312,7 @@ static int max8925_regulator_probe(struct platform_device *pdev) if (pdata) config.init_data = pdata; - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); @@ -323,22 +323,12 @@ static int max8925_regulator_probe(struct platform_device *pdev) return 0; } -static int max8925_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver max8925_regulator_driver = { .driver = { .name = "max8925-regulator", .owner = THIS_MODULE, }, .probe = max8925_regulator_probe, - .remove = max8925_regulator_remove, }; static int __init max8925_regulator_init(void) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 5b77ab7762e..892aa1e5b96 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -467,7 +467,7 @@ static int max8973_probe(struct i2c_client *client, config.regmap = max->regmap; /* Register the regulators */ - rdev = regulator_register(&max->desc, &config); + rdev = devm_regulator_register(&client->dev, &max->desc, &config); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(max->dev, "regulator register failed, err %d\n", ret); @@ -478,14 +478,6 @@ static int max8973_probe(struct i2c_client *client, return 0; } -static int max8973_remove(struct i2c_client *client) -{ - struct max8973_chip *max = i2c_get_clientdata(client); - - regulator_unregister(max->rdev); - return 0; -} - static const struct i2c_device_id max8973_id[] = { {.name = "max8973",}, {}, @@ -499,7 +491,6 @@ static struct i2c_driver max8973_i2c_driver = { .owner = THIS_MODULE, }, .probe = max8973_probe, - .remove = max8973_remove, .id_table = max8973_id, }; diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index df20069f053..2d618fc9c1a 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -690,8 +690,9 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, if (max8997->ignore_gpiodvs_side_effect == false) return -EINVAL; - dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:" - " %d -> %d\n", max8997->buck125_gpioindex, tmp_idx); + dev_warn(&rdev->dev, + "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET: %d -> %d\n", + max8997->buck125_gpioindex, tmp_idx); out: if (new_idx < 0 || new_val < 0) @@ -1081,7 +1082,7 @@ static int max8997_pmic_probe(struct platform_device *pdev) pdata->buck1_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_out; + return ret; max8997->buck2_vol[i] = ret = max8997_get_voltage_proper_val( @@ -1090,7 +1091,7 @@ static int max8997_pmic_probe(struct platform_device *pdev) pdata->buck2_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_out; + return ret; max8997->buck5_vol[i] = ret = max8997_get_voltage_proper_val( @@ -1099,7 +1100,7 @@ static int max8997_pmic_probe(struct platform_device *pdev) pdata->buck5_voltage[i] + buck1245_voltage_map_desc.step); if (ret < 0) - goto err_out; + return ret; if (max_buck1 < max8997->buck1_vol[i]) max_buck1 = max8997->buck1_vol[i]; @@ -1143,24 +1144,23 @@ static int max8997_pmic_probe(struct platform_device *pdev) !gpio_is_valid(pdata->buck125_gpios[1]) || !gpio_is_valid(pdata->buck125_gpios[2])) { dev_err(&pdev->dev, "GPIO NOT VALID\n"); - ret = -EINVAL; - goto err_out; + return -EINVAL; } ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0], "MAX8997 SET1"); if (ret) - goto err_out; + return ret; ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1], "MAX8997 SET2"); if (ret) - goto err_out; + return ret; ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2], "MAX8997 SET3"); if (ret) - goto err_out; + return ret; gpio_direction_output(pdata->buck125_gpios[0], (max8997->buck125_gpioindex >> 2) @@ -1205,33 +1205,16 @@ static int max8997_pmic_probe(struct platform_device *pdev) config.driver_data = max8997; config.of_node = pdata->regulators[i].reg_node; - rdev[i] = regulator_register(®ulators[id], &config); + rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); if (IS_ERR(rdev[i])) { - ret = PTR_ERR(rdev[i]); dev_err(max8997->dev, "regulator init failed for %d\n", id); - rdev[i] = NULL; - goto err; + return PTR_ERR(rdev[i]); } } return 0; -err: - while (--i >= 0) - regulator_unregister(rdev[i]); -err_out: - return ret; -} - -static int max8997_pmic_remove(struct platform_device *pdev) -{ - struct max8997_data *max8997 = platform_get_drvdata(pdev); - struct regulator_dev **rdev = max8997->rdev; - int i; - - for (i = 0; i < max8997->num_regulators; i++) - regulator_unregister(rdev[i]); - return 0; } static const struct platform_device_id max8997_pmic_id[] = { @@ -1246,7 +1229,6 @@ static struct platform_driver max8997_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8997_pmic_probe, - .remove = max8997_pmic_remove, .id_table = max8997_pmic_id, }; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index a4c53b2d1aa..ae3f0656feb 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -790,16 +790,14 @@ static int max8998_pmic_probe(struct platform_device *pdev) dev_err(&pdev->dev, "MAX8998 SET1 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set1); - ret = -EIO; - goto err_out; + return -EIO; } /* Check if SET2 is not equal to 0 */ if (!pdata->buck1_set2) { dev_err(&pdev->dev, "MAX8998 SET2 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck1_set2); - ret = -EIO; - goto err_out; + return -EIO; } gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); @@ -823,7 +821,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1 + v, i); if (ret) - goto err_out; + return ret; } } @@ -833,8 +831,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) dev_err(&pdev->dev, "MAX8998 SET3 GPIO defined as 0 !\n"); WARN_ON(!pdata->buck2_set3); - ret = -EIO; - goto err_out; + return -EIO; } gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); gpio_direction_output(pdata->buck2_set3, @@ -852,7 +849,7 @@ static int max8998_pmic_probe(struct platform_device *pdev) ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1 + v, i); if (ret) - goto err_out; + return ret; } } @@ -875,34 +872,19 @@ static int max8998_pmic_probe(struct platform_device *pdev) config.init_data = pdata->regulators[i].initdata; config.driver_data = max8998; - rdev[i] = regulator_register(®ulators[index], &config); + rdev[i] = devm_regulator_register(&pdev->dev, + ®ulators[index], &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(max8998->dev, "regulator %s init failed (%d)\n", regulators[index].name, ret); rdev[i] = NULL; - goto err; + return ret; } } return 0; -err: - while (--i >= 0) - regulator_unregister(rdev[i]); -err_out: - return ret; -} - -static int max8998_pmic_remove(struct platform_device *pdev) -{ - struct max8998_data *max8998 = platform_get_drvdata(pdev); - struct regulator_dev **rdev = max8998->rdev; - int i; - - for (i = 0; i < max8998->num_regulators; i++) - regulator_unregister(rdev[i]); - return 0; } static const struct platform_device_id max8998_pmic_id[] = { @@ -918,7 +900,6 @@ static struct platform_driver max8998_pmic_driver = { .owner = THIS_MODULE, }, .probe = max8998_pmic_probe, - .remove = max8998_pmic_remove, .id_table = max8998_pmic_id, }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 5ff99d2703d..7f4a67edf78 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -258,34 +258,34 @@ static struct mc13xxx_regulator mc13783_regulators[] = { MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), - MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, mc13783_violo_val), - MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, mc13783_vdig_val), - MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, mc13783_vgen_val), - MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfdig_val), - MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfref_val), - MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfcp_val), - MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, mc13783_vsim_val), - MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, mc13783_vesim_val), - MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, mc13783_vcam_val), MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), - MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, mc13783_vvib_val), - MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), - MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), @@ -400,7 +400,7 @@ static int mc13783_regulator_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev); struct mc13xxx_regulator_init_data *mc13xxx_data; struct regulator_config config = { }; - int i, ret, num_regulators; + int i, num_regulators; num_regulators = mc13xxx_get_num_regulators_dt(pdev); @@ -444,32 +444,16 @@ static int mc13783_regulator_probe(struct platform_device *pdev) config.driver_data = priv; config.of_node = node; - priv->regulators[i] = regulator_register(desc, &config); + priv->regulators[i] = devm_regulator_register(&pdev->dev, desc, + &config); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", mc13783_regulators[i].desc.name); - ret = PTR_ERR(priv->regulators[i]); - goto err; + return PTR_ERR(priv->regulators[i]); } } return 0; -err: - while (--i >= 0) - regulator_unregister(priv->regulators[i]); - - return ret; -} - -static int mc13783_regulator_remove(struct platform_device *pdev) -{ - struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < priv->num_regulators; i++) - regulator_unregister(priv->regulators[i]); - - return 0; } static struct platform_driver mc13783_regulator_driver = { @@ -477,7 +461,6 @@ static struct platform_driver mc13783_regulator_driver = { .name = "mc13783-regulator", .owner = THIS_MODULE, }, - .remove = mc13783_regulator_remove, .probe = mc13783_regulator_probe, }; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 1037e07937c..96c9f80d955 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -611,43 +611,27 @@ static int mc13892_regulator_probe(struct platform_device *pdev) config.driver_data = priv; config.of_node = node; - priv->regulators[i] = regulator_register(desc, &config); + priv->regulators[i] = devm_regulator_register(&pdev->dev, desc, + &config); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", mc13892_regulators[i].desc.name); - ret = PTR_ERR(priv->regulators[i]); - goto err; + return PTR_ERR(priv->regulators[i]); } } return 0; -err: - while (--i >= 0) - regulator_unregister(priv->regulators[i]); - return ret; err_unlock: mc13xxx_unlock(mc13892); return ret; } -static int mc13892_regulator_remove(struct platform_device *pdev) -{ - struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < priv->num_regulators; i++) - regulator_unregister(priv->regulators[i]); - - return 0; -} - static struct platform_driver mc13892_regulator_driver = { .driver = { .name = "mc13892-regulator", .owner = THIS_MODULE, }, - .remove = mc13892_regulator_remove, .probe = mc13892_regulator_probe, }; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 7827384680d..ea4f36f2cbe 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -23,6 +23,8 @@ static void of_get_regulation_constraints(struct device_node *np, const __be32 *min_uA, *max_uA, *ramp_delay; struct property *prop; struct regulation_constraints *constraints = &(*init_data)->constraints; + int ret; + u32 pval; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -73,6 +75,10 @@ static void of_get_regulation_constraints(struct device_node *np, else constraints->ramp_disable = true; } + + ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); + if (!ret) + constraints->enable_time = pval; } /** diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 7e2b165972e..9c62b1d3468 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -33,6 +33,7 @@ struct regs_info { u8 vsel_addr; u8 ctrl_addr; u8 tstep_addr; + int sleep_id; }; static const struct regs_info palmas_regs_info[] = { @@ -42,6 +43,7 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS12_VOLTAGE, .ctrl_addr = PALMAS_SMPS12_CTRL, .tstep_addr = PALMAS_SMPS12_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12, }, { .name = "SMPS123", @@ -49,12 +51,14 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS12_VOLTAGE, .ctrl_addr = PALMAS_SMPS12_CTRL, .tstep_addr = PALMAS_SMPS12_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12, }, { .name = "SMPS3", .sname = "smps3-in", .vsel_addr = PALMAS_SMPS3_VOLTAGE, .ctrl_addr = PALMAS_SMPS3_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS3, }, { .name = "SMPS45", @@ -62,6 +66,7 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS45_VOLTAGE, .ctrl_addr = PALMAS_SMPS45_CTRL, .tstep_addr = PALMAS_SMPS45_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45, }, { .name = "SMPS457", @@ -69,6 +74,7 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS45_VOLTAGE, .ctrl_addr = PALMAS_SMPS45_CTRL, .tstep_addr = PALMAS_SMPS45_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45, }, { .name = "SMPS6", @@ -76,12 +82,14 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS6_VOLTAGE, .ctrl_addr = PALMAS_SMPS6_CTRL, .tstep_addr = PALMAS_SMPS6_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS6, }, { .name = "SMPS7", .sname = "smps7-in", .vsel_addr = PALMAS_SMPS7_VOLTAGE, .ctrl_addr = PALMAS_SMPS7_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS7, }, { .name = "SMPS8", @@ -89,108 +97,128 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_SMPS8_VOLTAGE, .ctrl_addr = PALMAS_SMPS8_CTRL, .tstep_addr = PALMAS_SMPS8_TSTEP, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS8, }, { .name = "SMPS9", .sname = "smps9-in", .vsel_addr = PALMAS_SMPS9_VOLTAGE, .ctrl_addr = PALMAS_SMPS9_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS9, }, { .name = "SMPS10_OUT2", .sname = "smps10-in", .ctrl_addr = PALMAS_SMPS10_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10, }, { .name = "SMPS10_OUT1", .sname = "smps10-out2", .ctrl_addr = PALMAS_SMPS10_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10, }, { .name = "LDO1", .sname = "ldo1-in", .vsel_addr = PALMAS_LDO1_VOLTAGE, .ctrl_addr = PALMAS_LDO1_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO1, }, { .name = "LDO2", .sname = "ldo2-in", .vsel_addr = PALMAS_LDO2_VOLTAGE, .ctrl_addr = PALMAS_LDO2_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO2, }, { .name = "LDO3", .sname = "ldo3-in", .vsel_addr = PALMAS_LDO3_VOLTAGE, .ctrl_addr = PALMAS_LDO3_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO3, }, { .name = "LDO4", .sname = "ldo4-in", .vsel_addr = PALMAS_LDO4_VOLTAGE, .ctrl_addr = PALMAS_LDO4_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO4, }, { .name = "LDO5", .sname = "ldo5-in", .vsel_addr = PALMAS_LDO5_VOLTAGE, .ctrl_addr = PALMAS_LDO5_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO5, }, { .name = "LDO6", .sname = "ldo6-in", .vsel_addr = PALMAS_LDO6_VOLTAGE, .ctrl_addr = PALMAS_LDO6_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO6, }, { .name = "LDO7", .sname = "ldo7-in", .vsel_addr = PALMAS_LDO7_VOLTAGE, .ctrl_addr = PALMAS_LDO7_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO7, }, { .name = "LDO8", .sname = "ldo8-in", .vsel_addr = PALMAS_LDO8_VOLTAGE, .ctrl_addr = PALMAS_LDO8_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO8, }, { .name = "LDO9", .sname = "ldo9-in", .vsel_addr = PALMAS_LDO9_VOLTAGE, .ctrl_addr = PALMAS_LDO9_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO9, }, { .name = "LDOLN", .sname = "ldoln-in", .vsel_addr = PALMAS_LDOLN_VOLTAGE, .ctrl_addr = PALMAS_LDOLN_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOLN, }, { .name = "LDOUSB", .sname = "ldousb-in", .vsel_addr = PALMAS_LDOUSB_VOLTAGE, .ctrl_addr = PALMAS_LDOUSB_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOUSB, }, { .name = "REGEN1", .ctrl_addr = PALMAS_REGEN1_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN1, }, { .name = "REGEN2", .ctrl_addr = PALMAS_REGEN2_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN2, }, { .name = "REGEN3", .ctrl_addr = PALMAS_REGEN3_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN3, }, { .name = "SYSEN1", .ctrl_addr = PALMAS_SYSEN1_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN1, }, { .name = "SYSEN2", .ctrl_addr = PALMAS_SYSEN2_CTRL, + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN2, }, }; @@ -478,6 +506,17 @@ static struct regulator_ops palmas_ops_smps = { .set_ramp_delay = palmas_smps_set_ramp_delay, }; +static struct regulator_ops palmas_ops_ext_control_smps = { + .set_mode = palmas_set_mode_smps, + .get_mode = palmas_get_mode_smps, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = palmas_list_voltage_smps, + .map_voltage = palmas_map_voltage_smps, + .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel, + .set_ramp_delay = palmas_smps_set_ramp_delay, +}; + static struct regulator_ops palmas_ops_smps10 = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -513,12 +552,37 @@ static struct regulator_ops palmas_ops_ldo = { .map_voltage = regulator_map_voltage_linear, }; +static struct regulator_ops palmas_ops_ext_control_ldo = { + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, +}; + static struct regulator_ops palmas_ops_extreg = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, }; +static struct regulator_ops palmas_ops_ext_control_extreg = { +}; + +static int palmas_regulator_config_external(struct palmas *palmas, int id, + struct palmas_reg_init *reg_init) +{ + int sleep_id = palmas_regs_info[id].sleep_id; + int ret; + + ret = palmas_ext_control_req_config(palmas, sleep_id, + reg_init->roof_floor, true); + if (ret < 0) + dev_err(palmas->dev, + "Ext control config for regulator %d failed %d\n", + id, ret); + return ret; +} + /* * setup the hardware based sleep configuration of the SMPS/LDO regulators * from the platform data. This is different to the software based control @@ -577,7 +641,22 @@ static int palmas_smps_init(struct palmas *palmas, int id, return ret; } + if (reg_init->roof_floor && (id != PALMAS_REG_SMPS10_OUT1) && + (id != PALMAS_REG_SMPS10_OUT2)) { + /* Enable externally controlled regulator */ + addr = palmas_regs_info[id].ctrl_addr; + ret = palmas_smps_read(palmas, addr, ®); + if (ret < 0) + return ret; + if (!(reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK)) { + reg |= SMPS_CTRL_MODE_ON; + ret = palmas_smps_write(palmas, addr, reg); + if (ret < 0) + return ret; + } + return palmas_regulator_config_external(palmas, id, reg_init); + } return 0; } @@ -608,6 +687,20 @@ static int palmas_ldo_init(struct palmas *palmas, int id, if (ret) return ret; + if (reg_init->roof_floor) { + /* Enable externally controlled regulator */ + addr = palmas_regs_info[id].ctrl_addr; + ret = palmas_update_bits(palmas, PALMAS_LDO_BASE, + addr, PALMAS_LDO1_CTRL_MODE_ACTIVE, + PALMAS_LDO1_CTRL_MODE_ACTIVE); + if (ret < 0) { + dev_err(palmas->dev, + "LDO Register 0x%02x update failed %d\n", + addr, ret); + return ret; + } + return palmas_regulator_config_external(palmas, id, reg_init); + } return 0; } @@ -630,6 +723,21 @@ static int palmas_extreg_init(struct palmas *palmas, int id, addr, ret); return ret; } + + if (reg_init->roof_floor) { + /* Enable externally controlled regulator */ + addr = palmas_regs_info[id].ctrl_addr; + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE, + PALMAS_REGEN1_CTRL_MODE_ACTIVE); + if (ret < 0) { + dev_err(palmas->dev, + "Resource Register 0x%02x update failed %d\n", + addr, ret); + return ret; + } + return palmas_regulator_config_external(palmas, id, reg_init); + } return 0; } @@ -712,7 +820,7 @@ static void palmas_dt_to_pdata(struct device *dev, int idx, ret; node = of_node_get(node); - regulators = of_find_node_by_name(node, "regulators"); + regulators = of_get_child_by_name(node, "regulators"); if (!regulators) { dev_info(dev, "regulator node not found\n"); return; @@ -740,9 +848,35 @@ static void palmas_dt_to_pdata(struct device *dev, of_property_read_bool(palmas_matches[idx].of_node, "ti,warm-reset"); - pdata->reg_init[idx]->roof_floor = - of_property_read_bool(palmas_matches[idx].of_node, - "ti,roof-floor"); + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,roof-floor", &prop); + /* EINVAL: Property not found */ + if (ret != -EINVAL) { + int econtrol; + + /* use default value, when no value is specified */ + econtrol = PALMAS_EXT_CONTROL_NSLEEP; + if (!ret) { + switch (prop) { + case 1: + econtrol = PALMAS_EXT_CONTROL_ENABLE1; + break; + case 2: + econtrol = PALMAS_EXT_CONTROL_ENABLE2; + break; + case 3: + econtrol = PALMAS_EXT_CONTROL_NSLEEP; + break; + default: + WARN_ON(1); + dev_warn(dev, + "%s: Invalid roof-floor option: %u\n", + palmas_matches[idx].name, prop); + break; + } + } + pdata->reg_init[idx]->roof_floor = econtrol; + } ret = of_property_read_u32(palmas_matches[idx].of_node, "ti,mode-sleep", &prop); @@ -856,7 +990,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "reading TSTEP reg failed: %d\n", ret); - goto err_unregister_regulator; + return ret; } pmic->desc[id].ramp_delay = palmas_smps_ramp_delay[reg & 0x3]; @@ -868,7 +1002,9 @@ static int palmas_regulators_probe(struct platform_device *pdev) reg_init = pdata->reg_init[id]; ret = palmas_smps_init(palmas, id, reg_init); if (ret) - goto err_unregister_regulator; + return ret; + } else { + reg_init = NULL; } /* Register the regulators */ @@ -909,11 +1045,15 @@ static int palmas_regulators_probe(struct platform_device *pdev) ret = palmas_smps_read(pmic->palmas, addr, ®); if (ret) - goto err_unregister_regulator; + return ret; if (reg & PALMAS_SMPS12_VOLTAGE_RANGE) pmic->range[id] = 1; - pmic->desc[id].ops = &palmas_ops_smps; + if (reg_init && reg_init->roof_floor) + pmic->desc[id].ops = + &palmas_ops_ext_control_smps; + else + pmic->desc[id].ops = &palmas_ops_smps; pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, @@ -925,7 +1065,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) addr = palmas_regs_info[id].ctrl_addr; ret = palmas_smps_read(pmic->palmas, addr, ®); if (ret) - goto err_unregister_regulator; + return ret; pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; } @@ -941,13 +1081,13 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].supply_name = palmas_regs_info[id].sname; config.of_node = palmas_matches[id].of_node; - rdev = regulator_register(&pmic->desc[id], &config); + rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], + &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", pdev->name); - ret = PTR_ERR(rdev); - goto err_unregister_regulator; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ @@ -956,6 +1096,10 @@ static int palmas_regulators_probe(struct platform_device *pdev) /* Start this loop from the id left from previous loop */ for (; id < PALMAS_NUM_REGS; id++) { + if (pdata && pdata->reg_init[id]) + reg_init = pdata->reg_init[id]; + else + reg_init = NULL; /* Miss out regulators which are not available due * to alternate functions. @@ -969,7 +1113,11 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (id < PALMAS_REG_REGEN1) { pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; - pmic->desc[id].ops = &palmas_ops_ldo; + if (reg_init && reg_init->roof_floor) + pmic->desc[id].ops = + &palmas_ops_ext_control_ldo; + else + pmic->desc[id].ops = &palmas_ops_ldo; pmic->desc[id].min_uV = 900000; pmic->desc[id].uV_step = 50000; pmic->desc[id].linear_min_sel = 1; @@ -999,7 +1147,11 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].enable_time = 2000; } else { pmic->desc[id].n_voltages = 1; - pmic->desc[id].ops = &palmas_ops_extreg; + if (reg_init && reg_init->roof_floor) + pmic->desc[id].ops = + &palmas_ops_ext_control_extreg; + else + pmic->desc[id].ops = &palmas_ops_extreg; pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, palmas_regs_info[id].ctrl_addr); @@ -1015,13 +1167,13 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].supply_name = palmas_regs_info[id].sname; config.of_node = palmas_matches[id].of_node; - rdev = regulator_register(&pmic->desc[id], &config); + rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], + &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", pdev->name); - ret = PTR_ERR(rdev); - goto err_unregister_regulator; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ @@ -1037,31 +1189,14 @@ static int palmas_regulators_probe(struct platform_device *pdev) else ret = palmas_extreg_init(palmas, id, reg_init); - if (ret) { - regulator_unregister(pmic->rdev[id]); - goto err_unregister_regulator; - } + if (ret) + return ret; } } } return 0; - -err_unregister_regulator: - while (--id >= 0) - regulator_unregister(pmic->rdev[id]); - return ret; -} - -static int palmas_regulators_remove(struct platform_device *pdev) -{ - struct palmas_pmic *pmic = platform_get_drvdata(pdev); - int id; - - for (id = 0; id < PALMAS_NUM_REGS; id++) - regulator_unregister(pmic->rdev[id]); - return 0; } static struct of_device_id of_palmas_match_tbl[] = { @@ -1083,7 +1218,6 @@ static struct platform_driver palmas_driver = { .owner = THIS_MODULE, }, .probe = palmas_regulators_probe, - .remove = palmas_regulators_remove, }; static int __init palmas_init(void) diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index b49eaeedea8..3727b7d0e9a 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -246,7 +246,8 @@ static int pcap_regulator_probe(struct platform_device *pdev) config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = pcap; - rdev = regulator_register(&pcap_regulators[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, &pcap_regulators[pdev->id], + &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -255,22 +256,12 @@ static int pcap_regulator_probe(struct platform_device *pdev) return 0; } -static int pcap_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver pcap_regulator_driver = { .driver = { .name = "pcap-regulator", .owner = THIS_MODULE, }, .probe = pcap_regulator_probe, - .remove = pcap_regulator_remove, }; static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 0f3576d48ab..d7da1c15a6d 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -90,7 +90,8 @@ static int pcf50633_regulator_probe(struct platform_device *pdev) config.driver_data = pcf; config.regmap = pcf->regmap; - rdev = regulator_register(®ulators[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, ®ulators[pdev->id], + &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -102,21 +103,11 @@ static int pcf50633_regulator_probe(struct platform_device *pdev) return 0; } -static int pcf50633_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver pcf50633_regulator_driver = { .driver = { .name = "pcf50633-regltr", }, .probe = pcf50633_regulator_probe, - .remove = pcf50633_regulator_remove, }; static int __init pcf50633_regulator_init(void) diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 5885b450459..b58affb3314 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -173,33 +173,16 @@ skip_ext_pwr_config: config.driver_data = reg; config.regmap = rc5t583->regmap; - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); - ret = PTR_ERR(rdev); - goto clean_exit; + return PTR_ERR(rdev); } reg->rdev = rdev; } platform_set_drvdata(pdev, regs); return 0; - -clean_exit: - while (--id >= 0) - regulator_unregister(regs[id].rdev); - - return ret; -} - -static int rc5t583_regulator_remove(struct platform_device *pdev) -{ - struct rc5t583_regulator *regs = platform_get_drvdata(pdev); - int id; - - for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) - regulator_unregister(regs[id].rdev); - return 0; } static struct platform_driver rc5t583_regulator_driver = { @@ -208,7 +191,6 @@ static struct platform_driver rc5t583_regulator_driver = { .owner = THIS_MODULE, }, .probe = rc5t583_regulator_probe, - .remove = rc5t583_regulator_remove, }; static int __init rc5t583_regulator_init(void) diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 5eba2ff8c0e..333677d68d0 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -448,33 +448,17 @@ common_reg: config.of_node = rdata[i].of_node; } - s2mps11->rdev[i] = regulator_register(®ulators[i], &config); + s2mps11->rdev[i] = devm_regulator_register(&pdev->dev, + ®ulators[i], &config); if (IS_ERR(s2mps11->rdev[i])) { ret = PTR_ERR(s2mps11->rdev[i]); dev_err(&pdev->dev, "regulator init failed for %d\n", i); - s2mps11->rdev[i] = NULL; - goto err; + return ret; } } return 0; -err: - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) - regulator_unregister(s2mps11->rdev[i]); - - return ret; -} - -static int s2mps11_pmic_remove(struct platform_device *pdev) -{ - struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) - regulator_unregister(s2mps11->rdev[i]); - - return 0; } static const struct platform_device_id s2mps11_pmic_id[] = { @@ -489,7 +473,6 @@ static struct platform_driver s2mps11_pmic_driver = { .owner = THIS_MODULE, }, .probe = s2mps11_pmic_probe, - .remove = s2mps11_pmic_remove, .id_table = s2mps11_pmic_id, }; diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index c24448bc43c..cbf91e25cf7 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -522,7 +522,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, struct device_node *pmic_np, *regulators_np, *reg_np; struct sec_regulator_data *rdata; struct sec_opmode_data *rmode; - unsigned int i, dvs_voltage_nr = 1, ret; + unsigned int i, dvs_voltage_nr = 8, ret; pmic_np = iodev->dev->of_node; if (!pmic_np) { @@ -586,15 +586,39 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rmode++; } - if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) + if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) { pdata->buck2_gpiodvs = true; - if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck2-dvs-voltage", + pdata->buck2_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck2 voltages not specified\n"); + return -EINVAL; + } + } + + if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) { pdata->buck3_gpiodvs = true; - if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck3-dvs-voltage", + pdata->buck3_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck3 voltages not specified\n"); + return -EINVAL; + } + } + + if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) { pdata->buck4_gpiodvs = true; + if (of_property_read_u32_array(pmic_np, + "s5m8767,pmic-buck4-dvs-voltage", + pdata->buck4_voltage, dvs_voltage_nr)) { + dev_err(iodev->dev, "buck4 voltages not specified\n"); + return -EINVAL; + } + } + if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); @@ -612,32 +636,26 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, "invalid value for default dvs index, use 0\n"); } } - dvs_voltage_nr = 8; } ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); if (ret) return -EINVAL; - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck2-dvs-voltage", - pdata->buck2_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck2 voltages not specified\n"); - return -EINVAL; - } + if (of_get_property(pmic_np, "s5m8767,pmic-buck2-ramp-enable", NULL)) + pdata->buck2_ramp_enable = true; - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck3-dvs-voltage", - pdata->buck3_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck3 voltages not specified\n"); - return -EINVAL; - } + if (of_get_property(pmic_np, "s5m8767,pmic-buck3-ramp-enable", NULL)) + pdata->buck3_ramp_enable = true; - if (of_property_read_u32_array(pmic_np, - "s5m8767,pmic-buck4-dvs-voltage", - pdata->buck4_voltage, dvs_voltage_nr)) { - dev_err(iodev->dev, "buck4 voltages not specified\n"); - return -EINVAL; + if (of_get_property(pmic_np, "s5m8767,pmic-buck4-ramp-enable", NULL)) + pdata->buck4_ramp_enable = true; + + if (pdata->buck2_ramp_enable || pdata->buck3_ramp_enable + || pdata->buck4_ramp_enable) { + if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-ramp-delay", + &pdata->buck_ramp_delay)) + pdata->buck_ramp_delay = 0; } return 0; @@ -910,34 +928,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.regmap = iodev->regmap; config.of_node = pdata->regulators[i].reg_node; - rdev[i] = regulator_register(®ulators[id], &config); + rdev[i] = devm_regulator_register(&pdev->dev, ®ulators[id], + &config); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(s5m8767->dev, "regulator init failed for %d\n", id); - rdev[i] = NULL; - goto err; + return ret; } } return 0; -err: - for (i = 0; i < s5m8767->num_regulators; i++) - regulator_unregister(rdev[i]); - - return ret; -} - -static int s5m8767_pmic_remove(struct platform_device *pdev) -{ - struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); - struct regulator_dev **rdev = s5m8767->rdev; - int i; - - for (i = 0; i < s5m8767->num_regulators; i++) - regulator_unregister(rdev[i]); - - return 0; } static const struct platform_device_id s5m8767_pmic_id[] = { @@ -952,7 +953,6 @@ static struct platform_driver s5m8767_pmic_driver = { .owner = THIS_MODULE, }, .probe = s5m8767_pmic_probe, - .remove = s5m8767_pmic_remove, .id_table = s5m8767_pmic_id, }; diff --git a/drivers/regulator/stw481x-vmmc.c b/drivers/regulator/stw481x-vmmc.c new file mode 100644 index 00000000000..f78857bd6a1 --- /dev/null +++ b/drivers/regulator/stw481x-vmmc.c @@ -0,0 +1,111 @@ +/* + * Regulator driver for STw4810/STw4811 VMMC regulator. + * + * Copyright (C) 2013 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/stw481x.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +static const unsigned int stw481x_vmmc_voltages[] = { + 1800000, + 1800000, + 2850000, + 3000000, + 1850000, + 2600000, + 2700000, + 3300000, +}; + +static struct regulator_ops stw481x_vmmc_ops = { + .list_voltage = regulator_list_voltage_table, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static struct regulator_desc vmmc_regulator = { + .name = "VMMC", + .id = 0, + .ops = &stw481x_vmmc_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(stw481x_vmmc_voltages), + .volt_table = stw481x_vmmc_voltages, + .enable_time = 200, /* FIXME: look this up */ + .enable_reg = STW_CONF1, + .enable_mask = STW_CONF1_PDN_VMMC, + .vsel_reg = STW_CONF1, + .vsel_mask = STW_CONF1_VMMC_MASK, +}; + +static int stw481x_vmmc_regulator_probe(struct platform_device *pdev) +{ + struct stw481x *stw481x = dev_get_platdata(&pdev->dev); + struct regulator_config config = { }; + int ret; + + /* First disable the external VMMC if it's active */ + ret = regmap_update_bits(stw481x->map, STW_CONF2, + STW_CONF2_VMMC_EXT, 0); + if (ret) { + dev_err(&pdev->dev, "could not disable external VMMC\n"); + return ret; + } + + /* Register VMMC regulator */ + config.dev = &pdev->dev; + config.driver_data = stw481x; + config.regmap = stw481x->map; + config.of_node = pdev->dev.of_node; + config.init_data = of_get_regulator_init_data(&pdev->dev, + pdev->dev.of_node); + + stw481x->vmmc_regulator = regulator_register(&vmmc_regulator, &config); + if (IS_ERR(stw481x->vmmc_regulator)) { + dev_err(&pdev->dev, + "error initializing STw481x VMMC regulator\n"); + return PTR_ERR(stw481x->vmmc_regulator); + } + + dev_info(&pdev->dev, "initialized STw481x VMMC regulator\n"); + return 0; +} + +static int stw481x_vmmc_regulator_remove(struct platform_device *pdev) +{ + struct stw481x *stw481x = dev_get_platdata(&pdev->dev); + + regulator_unregister(stw481x->vmmc_regulator); + return 0; +} + +static const struct of_device_id stw481x_vmmc_match[] = { + { .compatible = "st,stw481x-vmmc", }, + {}, +}; + +static struct platform_driver stw481x_vmmc_regulator_driver = { + .driver = { + .name = "stw481x-vmmc-regulator", + .owner = THIS_MODULE, + .of_match_table = stw481x_vmmc_match, + }, + .probe = stw481x_vmmc_regulator_probe, + .remove = stw481x_vmmc_regulator_remove, +}; + +module_platform_driver(stw481x_vmmc_regulator_driver); diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index 20c271d49dc..b187b6bba7a 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -615,7 +615,7 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, pname, *volt_table, vset_mask); continue; } - info->vset = efuse_val & vset_mask >> __ffs(vset_mask); + info->vset = (efuse_val & vset_mask) >> __ffs(vset_mask); dev_dbg(dev, "[%d]v=%d vset=%x\n", i, *volt_table, info->vset); check_abb: switch (info->opp_sel) { @@ -708,39 +708,31 @@ static int ti_abb_probe(struct platform_device *pdev) match = of_match_device(ti_abb_of_match, dev); if (!match) { /* We do not expect this to happen */ - ret = -ENODEV; dev_err(dev, "%s: Unable to match device\n", __func__); - goto err; + return -ENODEV; } if (!match->data) { - ret = -EINVAL; dev_err(dev, "%s: Bad data in match\n", __func__); - goto err; + return -EINVAL; } abb = devm_kzalloc(dev, sizeof(struct ti_abb), GFP_KERNEL); - if (!abb) { - dev_err(dev, "%s: Unable to allocate ABB struct\n", __func__); - ret = -ENOMEM; - goto err; - } + if (!abb) + return -ENOMEM; abb->regs = match->data; /* Map ABB resources */ pname = "base-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); abb->base = devm_ioremap_resource(dev, res); - if (IS_ERR(abb->base)) { - ret = PTR_ERR(abb->base); - goto err; - } + if (IS_ERR(abb->base)) + return PTR_ERR(abb->base); pname = "int-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); if (!res) { dev_err(dev, "Missing '%s' IO resource\n", pname); - ret = -ENODEV; - goto err; + return -ENODEV; } /* * We may have shared interrupt register offsets which are @@ -750,8 +742,7 @@ static int ti_abb_probe(struct platform_device *pdev) resource_size(res)); if (!abb->int_base) { dev_err(dev, "Unable to map '%s'\n", pname); - ret = -ENOMEM; - goto err; + return -ENOMEM; } /* Map Optional resources */ @@ -771,17 +762,19 @@ static int ti_abb_probe(struct platform_device *pdev) resource_size(res)); if (!abb->efuse_base) { dev_err(dev, "Unable to map '%s'\n", pname); - ret = -ENOMEM; - goto err; + return -ENOMEM; } pname = "ldo-address"; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); - abb->ldo_base = devm_ioremap_resource(dev, res); - if (IS_ERR(abb->ldo_base)) { - ret = PTR_ERR(abb->ldo_base); - goto err; + if (!res) { + dev_dbg(dev, "Missing '%s' IO resource\n", pname); + ret = -ENODEV; + goto skip_opt; } + abb->ldo_base = devm_ioremap_resource(dev, res); + if (IS_ERR(abb->ldo_base)) + return PTR_ERR(abb->ldo_base); /* IF ldo_base is set, the following are mandatory */ pname = "ti,ldovbb-override-mask"; @@ -790,12 +783,11 @@ static int ti_abb_probe(struct platform_device *pdev) &abb->ldovbb_override_mask); if (ret) { dev_err(dev, "Missing '%s' (%d)\n", pname, ret); - goto err; + return ret; } if (!abb->ldovbb_override_mask) { dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); - ret = -EINVAL; - goto err; + return -EINVAL; } pname = "ti,ldovbb-vset-mask"; @@ -804,12 +796,11 @@ static int ti_abb_probe(struct platform_device *pdev) &abb->ldovbb_vset_mask); if (ret) { dev_err(dev, "Missing '%s' (%d)\n", pname, ret); - goto err; + return ret; } if (!abb->ldovbb_vset_mask) { dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); - ret = -EINVAL; - goto err; + return -EINVAL; } skip_opt: @@ -819,31 +810,29 @@ skip_opt: &abb->txdone_mask); if (ret) { dev_err(dev, "Missing '%s' (%d)\n", pname, ret); - goto err; + return ret; } if (!abb->txdone_mask) { dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); - ret = -EINVAL; - goto err; + return -EINVAL; } initdata = of_get_regulator_init_data(dev, pdev->dev.of_node); if (!initdata) { - ret = -ENOMEM; dev_err(dev, "%s: Unable to alloc regulator init data\n", __func__); - goto err; + return -ENOMEM; } /* init ABB opp_sel table */ ret = ti_abb_init_table(dev, abb, initdata); if (ret) - goto err; + return ret; /* init ABB timing */ ret = ti_abb_init_timings(dev, abb); if (ret) - goto err; + return ret; desc = &abb->rdesc; desc->name = dev_name(dev); @@ -861,12 +850,12 @@ skip_opt: config.driver_data = abb; config.of_node = pdev->dev.of_node; - rdev = regulator_register(desc, &config); + rdev = devm_regulator_register(dev, desc, &config); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(dev, "%s: failed to register regulator(%d)\n", __func__, ret); - goto err; + return ret; } platform_set_drvdata(pdev, rdev); @@ -874,31 +863,12 @@ skip_opt: ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base); return 0; - -err: - dev_err(dev, "%s: Failed to initialize(%d)\n", __func__, ret); - return ret; -} - -/** - * ti_abb_remove() - cleanups - * @pdev: ABB platform device - * - * Return: 0 - */ -static int ti_abb_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - return 0; } MODULE_ALIAS("platform:ti_abb"); static struct platform_driver ti_abb_driver = { .probe = ti_abb_probe, - .remove = ti_abb_remove, .driver = { .name = "ti_abb", .owner = THIS_MODULE, diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 9392a7ca3d2..b0a3f0917a2 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -343,7 +343,7 @@ static int tps51632_probe(struct i2c_client *client, config.regmap = tps->regmap; config.of_node = client->dev.of_node; - rdev = regulator_register(&tps->desc, &config); + rdev = devm_regulator_register(&client->dev, &tps->desc, &config); if (IS_ERR(rdev)) { dev_err(tps->dev, "regulator register failed\n"); return PTR_ERR(rdev); @@ -353,14 +353,6 @@ static int tps51632_probe(struct i2c_client *client, return 0; } -static int tps51632_remove(struct i2c_client *client) -{ - struct tps51632_chip *tps = i2c_get_clientdata(client); - - regulator_unregister(tps->rdev); - return 0; -} - static const struct i2c_device_id tps51632_id[] = { {.name = "tps51632",}, {}, @@ -375,7 +367,6 @@ static struct i2c_driver tps51632_i2c_driver = { .of_match_table = of_match_ptr(tps51632_of_match), }, .probe = tps51632_probe, - .remove = tps51632_remove, .id_table = tps51632_id, }; diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index ec9453ffb77..c1e33a3d397 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -137,7 +137,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) /* This instance is not set for regulator mode so bail out */ if (pdata->mode != TPS6105X_MODE_VOLTAGE) { dev_info(&pdev->dev, - "chip not in voltage mode mode, exit probe \n"); + "chip not in voltage mode mode, exit probe\n"); return 0; } @@ -146,8 +146,9 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) config.driver_data = tps6105x; /* Register regulator with framework */ - tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, - &config); + tps6105x->regulator = devm_regulator_register(&pdev->dev, + &tps6105x_regulator_desc, + &config); if (IS_ERR(tps6105x->regulator)) { ret = PTR_ERR(tps6105x->regulator); dev_err(&tps6105x->client->dev, @@ -159,20 +160,12 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) return 0; } -static int tps6105x_regulator_remove(struct platform_device *pdev) -{ - struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); - regulator_unregister(tps6105x->regulator); - return 0; -} - static struct platform_driver tps6105x_regulator_driver = { .driver = { .name = "tps6105x-regulator", .owner = THIS_MODULE, }, .probe = tps6105x_regulator_probe, - .remove = tps6105x_regulator_remove, }; static __init int tps6105x_regulator_init(void) diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 0b7ebb1ebf8..c2c0185a2dc 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -476,7 +476,7 @@ static int tps62360_probe(struct i2c_client *client, config.of_node = client->dev.of_node; /* Register the regulators */ - rdev = regulator_register(&tps->desc, &config); + rdev = devm_regulator_register(&client->dev, &tps->desc, &config); if (IS_ERR(rdev)) { dev_err(tps->dev, "%s(): regulator register failed with err %s\n", @@ -488,20 +488,6 @@ static int tps62360_probe(struct i2c_client *client, return 0; } -/** - * tps62360_remove - tps62360 driver i2c remove handler - * @client: i2c driver client device structure - * - * Unregister TPS driver as an i2c client device driver - */ -static int tps62360_remove(struct i2c_client *client) -{ - struct tps62360_chip *tps = i2c_get_clientdata(client); - - regulator_unregister(tps->rdev); - return 0; -} - static void tps62360_shutdown(struct i2c_client *client) { struct tps62360_chip *tps = i2c_get_clientdata(client); @@ -535,7 +521,6 @@ static struct i2c_driver tps62360_i2c_driver = { .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, - .remove = tps62360_remove, .shutdown = tps62360_shutdown, .id_table = tps62360_id, }; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index a15263d4bdf..3ef67a86115 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -277,12 +277,12 @@ static int tps_65023_probe(struct i2c_client *client, config.regmap = tps->regmap; /* Register the regulators */ - rdev = regulator_register(&tps->desc[i], &config); + rdev = devm_regulator_register(&client->dev, &tps->desc[i], + &config); if (IS_ERR(rdev)) { dev_err(&client->dev, "failed to register %s\n", id->name); - error = PTR_ERR(rdev); - goto fail; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ @@ -293,24 +293,10 @@ static int tps_65023_probe(struct i2c_client *client, /* Enable setting output voltage by I2C */ regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, - TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ); + TPS65023_REG_CTRL2_CORE_ADJ, + TPS65023_REG_CTRL2_CORE_ADJ); return 0; - - fail: - while (--i >= 0) - regulator_unregister(tps->rdev[i]); - return error; -} - -static int tps_65023_remove(struct i2c_client *client) -{ - struct tps_pmic *tps = i2c_get_clientdata(client); - int i; - - for (i = 0; i < TPS65023_NUM_REGULATOR; i++) - regulator_unregister(tps->rdev[i]); - return 0; } static const struct tps_info tps65020_regs[] = { @@ -430,7 +416,6 @@ static struct i2c_driver tps_65023_i2c_driver = { .owner = THIS_MODULE, }, .probe = tps_65023_probe, - .remove = tps_65023_remove, .id_table = tps_65023_id, }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 4117ff52dba..162a0fae20b 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -508,13 +508,13 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) config.of_node = tps6507x_reg_matches[i].of_node; } - rdev = regulator_register(&tps->desc[i], &config); + rdev = devm_regulator_register(&pdev->dev, &tps->desc[i], + &config); if (IS_ERR(rdev)) { dev_err(tps6507x_dev->dev, "failed to register %s regulator\n", pdev->name); - error = PTR_ERR(rdev); - goto fail; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ @@ -525,22 +525,6 @@ static int tps6507x_pmic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tps6507x_dev); return 0; - -fail: - while (--i >= 0) - regulator_unregister(tps->rdev[i]); - return error; -} - -static int tps6507x_pmic_remove(struct platform_device *pdev) -{ - struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); - struct tps6507x_pmic *tps = tps6507x_dev->pmic; - int i; - - for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) - regulator_unregister(tps->rdev[i]); - return 0; } static struct platform_driver tps6507x_pmic_driver = { @@ -549,7 +533,6 @@ static struct platform_driver tps6507x_pmic_driver = { .owner = THIS_MODULE, }, .probe = tps6507x_pmic_probe, - .remove = tps6507x_pmic_remove, }; static int __init tps6507x_pmic_init(void) diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index c8e70451df3..676f75548f0 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -180,7 +180,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data( return ERR_PTR(-ENOMEM); } - regulators = of_find_node_by_name(np, "regulators"); + regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulator node not found\n"); return ERR_PTR(-ENODEV); @@ -279,7 +279,7 @@ static int tps65090_regulator_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "failed disable ext control\n"); - goto scrub; + return ret; } } } @@ -296,12 +296,11 @@ static int tps65090_regulator_probe(struct platform_device *pdev) else config.of_node = NULL; - rdev = regulator_register(ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc->name); - ret = PTR_ERR(rdev); - goto scrub; + return PTR_ERR(rdev); } ri->rdev = rdev; @@ -309,36 +308,13 @@ static int tps65090_regulator_probe(struct platform_device *pdev) if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data && tps_pdata->enable_ext_control) { ret = tps65090_config_ext_control(ri, true); - if (ret < 0) { - /* Increment num to get unregister rdev */ - num++; - goto scrub; - } + if (ret < 0) + return ret; } } platform_set_drvdata(pdev, pmic); return 0; - -scrub: - while (--num >= 0) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return ret; -} - -static int tps65090_regulator_remove(struct platform_device *pdev) -{ - struct tps65090_regulator *pmic = platform_get_drvdata(pdev); - struct tps65090_regulator *ri; - int num; - - for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return 0; } static struct platform_driver tps65090_regulator_driver = { @@ -347,7 +323,6 @@ static struct platform_driver tps65090_regulator_driver = { .owner = THIS_MODULE, }, .probe = tps65090_regulator_probe, - .remove = tps65090_regulator_remove, }; static int __init tps65090_regulator_init(void) diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 90861d68a0b..9ea1bf26bd1 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -52,25 +52,17 @@ static const unsigned int LDO1_VSEL_table[] = { }; static const struct regulator_linear_range tps65217_uv1_ranges[] = { - { .min_uV = 900000, .max_uV = 1500000, .min_sel = 0, .max_sel = 24, - .uV_step = 25000 }, - { .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30, - .uV_step = 50000 }, - { .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52, - .uV_step = 50000 }, - { .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55, - .uV_step = 100000 }, - { .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62, - .uV_step = 0 }, + REGULATOR_LINEAR_RANGE(900000, 0, 24, 25000), + REGULATOR_LINEAR_RANGE(1550000, 25, 30, 50000), + REGULATOR_LINEAR_RANGE(1850000, 31, 52, 50000), + REGULATOR_LINEAR_RANGE(3000000, 53, 55, 100000), + REGULATOR_LINEAR_RANGE(3300000, 56, 62, 0), }; static const struct regulator_linear_range tps65217_uv2_ranges[] = { - { .min_uV = 1500000, .max_uV = 1900000, .min_sel = 0, .max_sel = 8, - .uV_step = 50000 }, - { .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13, - .uV_step = 100000 }, - { .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31, - .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(1500000, 0, 8, 50000), + REGULATOR_LINEAR_RANGE(2000000, 9, 13, 100000), + REGULATOR_LINEAR_RANGE(2450000, 14, 31, 50000), }; static int tps65217_pmic_enable(struct regulator_dev *dev) @@ -233,7 +225,7 @@ static int tps65217_regulator_probe(struct platform_device *pdev) struct regulator_init_data *reg_data; struct regulator_dev *rdev; struct regulator_config config = { }; - int i, ret; + int i; if (tps->dev->of_node) pdata = tps65217_parse_dt(pdev); @@ -269,35 +261,18 @@ static int tps65217_regulator_probe(struct platform_device *pdev) if (tps->dev->of_node) config.of_node = pdata->of_node[i]; - rdev = regulator_register(®ulators[i], &config); + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], + &config); if (IS_ERR(rdev)) { dev_err(tps->dev, "failed to register %s regulator\n", pdev->name); - ret = PTR_ERR(rdev); - goto err_unregister_regulator; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ tps->rdev[i] = rdev; } return 0; - -err_unregister_regulator: - while (--i >= 0) - regulator_unregister(tps->rdev[i]); - - return ret; -} - -static int tps65217_regulator_remove(struct platform_device *pdev) -{ - struct tps65217 *tps = platform_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < TPS65217_NUM_REGULATOR; i++) - regulator_unregister(tps->rdev[i]); - - return 0; } static struct platform_driver tps65217_regulator_driver = { @@ -305,7 +280,6 @@ static struct platform_driver tps65217_regulator_driver = { .name = "tps65217-pmic", }, .probe = tps65217_regulator_probe, - .remove = tps65217_regulator_remove, }; static int __init tps65217_regulator_init(void) diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 62e8d28beab..9f6bfda711b 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -577,21 +577,6 @@ static struct regulator_ops regulator_ops = { .get_current_limit = get_current_limit, }; -static int pmic_remove(struct spi_device *spi) -{ - struct tps6524x *hw = spi_get_drvdata(spi); - int i; - - if (!hw) - return 0; - for (i = 0; i < N_REGULATORS; i++) { - regulator_unregister(hw->rdev[i]); - hw->rdev[i] = NULL; - } - spi_set_drvdata(spi, NULL); - return 0; -} - static int pmic_probe(struct spi_device *spi) { struct tps6524x *hw; @@ -599,7 +584,7 @@ static int pmic_probe(struct spi_device *spi) const struct supply_info *info = supply_info; struct regulator_init_data *init_data; struct regulator_config config = { }; - int ret = 0, i; + int i; init_data = dev_get_platdata(dev); if (!init_data) { @@ -632,24 +617,17 @@ static int pmic_probe(struct spi_device *spi) config.init_data = init_data; config.driver_data = hw; - hw->rdev[i] = regulator_register(&hw->desc[i], &config); - if (IS_ERR(hw->rdev[i])) { - ret = PTR_ERR(hw->rdev[i]); - hw->rdev[i] = NULL; - goto fail; - } + hw->rdev[i] = devm_regulator_register(dev, &hw->desc[i], + &config); + if (IS_ERR(hw->rdev[i])) + return PTR_ERR(hw->rdev[i]); } return 0; - -fail: - pmic_remove(spi); - return ret; } static struct spi_driver pmic_driver = { .probe = pmic_probe, - .remove = pmic_remove, .driver = { .name = "tps6524x", .owner = THIS_MODULE, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 2c9155b66f0..e8e3a8afd3e 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -298,7 +298,7 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( struct tps6586x_platform_data *pdata; int err; - regs = of_find_node_by_name(np, "regulators"); + regs = of_get_child_by_name(np, "regulators"); if (!regs) { dev_err(&pdev->dev, "regulator node not found\n"); return NULL; @@ -379,15 +379,14 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) ri = find_regulator_info(id); if (!ri) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); - err = -EINVAL; - goto fail; + return -EINVAL; } err = tps6586x_regulator_preinit(pdev->dev.parent, ri); if (err) { dev_err(&pdev->dev, "regulator %d preinit failed, e %d\n", id, err); - goto fail; + return err; } config.dev = pdev->dev.parent; @@ -397,12 +396,12 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) if (tps6586x_reg_matches) config.of_node = tps6586x_reg_matches[id].of_node; - rdev[id] = regulator_register(&ri->desc, &config); + rdev[id] = devm_regulator_register(&pdev->dev, &ri->desc, + &config); if (IS_ERR(rdev[id])) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); - err = PTR_ERR(rdev[id]); - goto fail; + return PTR_ERR(rdev[id]); } if (reg_data) { @@ -411,30 +410,13 @@ static int tps6586x_regulator_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "Slew rate config failed, e %d\n", err); - regulator_unregister(rdev[id]); - goto fail; + return err; } } } platform_set_drvdata(pdev, rdev); return 0; - -fail: - while (--id >= 0) - regulator_unregister(rdev[id]); - return err; -} - -static int tps6586x_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev **rdev = platform_get_drvdata(pdev); - int id = TPS6586X_ID_MAX_REGULATOR; - - while (--id >= 0) - regulator_unregister(rdev[id]); - - return 0; } static struct platform_driver tps6586x_regulator_driver = { @@ -443,7 +425,6 @@ static struct platform_driver tps6586x_regulator_driver = { .owner = THIS_MODULE, }, .probe = tps6586x_regulator_probe, - .remove = tps6586x_regulator_remove, }; static int __init tps6586x_regulator_init(void) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 45c16447744..23f8d1ce877 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -481,7 +481,7 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) /* multiplier 0 == 1 but 2,3 normal */ if (!mult) - mult=1; + mult = 1; if (sr) { /* normalise to valid range */ @@ -685,7 +685,7 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, case TPS65910_REG_VDD2: mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; volt = VDD1_2_MIN_VOLT + - (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; + (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; break; case TPS65911_REG_VDDCTRL: volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); @@ -703,7 +703,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector) struct tps65910_reg *pmic = rdev_get_drvdata(dev); int step_mv = 0, id = rdev_get_id(dev); - switch(id) { + switch (id) { case TPS65911_REG_LDO1: case TPS65911_REG_LDO2: case TPS65911_REG_LDO4: @@ -982,7 +982,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data( } np = of_node_get(pdev->dev.parent->of_node); - regulators = of_find_node_by_name(np, "regulators"); + regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulator node not found\n"); return NULL; @@ -1074,7 +1074,7 @@ static int tps65910_probe(struct platform_device *pdev) tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, DEVCTRL_SR_CTL_I2C_SEL_MASK); - switch(tps65910_chip_id(tps65910)) { + switch (tps65910_chip_id(tps65910)) { case TPS65910: pmic->get_ctrl_reg = &tps65910_get_ctrl_register; pmic->num_regulators = ARRAY_SIZE(tps65910_regs); @@ -1177,35 +1177,19 @@ static int tps65910_probe(struct platform_device *pdev) if (tps65910_reg_matches) config.of_node = tps65910_reg_matches[i].of_node; - rdev = regulator_register(&pmic->desc[i], &config); + rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], + &config); if (IS_ERR(rdev)) { dev_err(tps65910->dev, "failed to register %s regulator\n", pdev->name); - err = PTR_ERR(rdev); - goto err_unregister_regulator; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ pmic->rdev[i] = rdev; } return 0; - -err_unregister_regulator: - while (--i >= 0) - regulator_unregister(pmic->rdev[i]); - return err; -} - -static int tps65910_remove(struct platform_device *pdev) -{ - struct tps65910_reg *pmic = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < pmic->num_regulators; i++) - regulator_unregister(pmic->rdev[i]); - - return 0; } static void tps65910_shutdown(struct platform_device *pdev) @@ -1244,7 +1228,6 @@ static struct platform_driver tps65910_driver = { .owner = THIS_MODULE, }, .probe = tps65910_probe, - .remove = tps65910_remove, .shutdown = tps65910_shutdown, }; diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 281e52ac64b..9cafaa0f945 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -119,12 +119,9 @@ struct tps65912_reg { }; static const struct regulator_linear_range tps65912_ldo_ranges[] = { - { .min_uV = 800000, .max_uV = 1600000, .min_sel = 0, .max_sel = 32, - .uV_step = 25000 }, - { .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60, - .uV_step = 50000 }, - { .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(800000, 0, 32, 25000), + REGULATOR_LINEAR_RANGE(1650000, 33, 60, 50000), + REGULATOR_LINEAR_RANGE(3100000, 61, 63, 100000), }; static int tps65912_get_range(struct tps65912_reg *pmic, int id) @@ -461,7 +458,7 @@ static int tps65912_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct tps65912_reg *pmic; struct tps65912_board *pmic_plat_data; - int i, err; + int i; pmic_plat_data = dev_get_platdata(tps65912->dev); if (!pmic_plat_data) @@ -504,34 +501,19 @@ static int tps65912_probe(struct platform_device *pdev) config.init_data = reg_data; config.driver_data = pmic; - rdev = regulator_register(&pmic->desc[i], &config); + rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], + &config); if (IS_ERR(rdev)) { dev_err(tps65912->dev, "failed to register %s regulator\n", pdev->name); - err = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } /* Save regulator for cleanup */ pmic->rdev[i] = rdev; } return 0; - -err: - while (--i >= 0) - regulator_unregister(pmic->rdev[i]); - return err; -} - -static int tps65912_remove(struct platform_device *pdev) -{ - struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < TPS65912_NUM_REGULATOR; i++) - regulator_unregister(tps65912_reg->rdev[i]); - return 0; } static struct platform_driver tps65912_driver = { @@ -540,7 +522,6 @@ static struct platform_driver tps65912_driver = { .owner = THIS_MODULE, }, .probe = tps65912_probe, - .remove = tps65912_remove, }; static int __init tps65912_init(void) diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 6511d0bfd89..71f457a4262 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -719,7 +719,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "regulator config failed, e %d\n", ret); - goto fail; + return ret; } ret = tps80031_power_req_config(pdev->dev.parent, @@ -727,41 +727,22 @@ static int tps80031_regulator_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "pwr_req config failed, err %d\n", ret); - goto fail; + return ret; } } - rdev = regulator_register(&ri->rinfo->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->rinfo->desc, + &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "register regulator failed %s\n", ri->rinfo->desc.name); - ret = PTR_ERR(rdev); - goto fail; + return PTR_ERR(rdev); } ri->rdev = rdev; } platform_set_drvdata(pdev, pmic); return 0; -fail: - while (--num >= 0) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return ret; -} - -static int tps80031_regulator_remove(struct platform_device *pdev) -{ - struct tps80031_regulator *pmic = platform_get_drvdata(pdev); - struct tps80031_regulator *ri = NULL; - int num; - - for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return 0; } static struct platform_driver tps80031_regulator_driver = { @@ -770,7 +751,6 @@ static struct platform_driver tps80031_regulator_driver = { .owner = THIS_MODULE, }, .probe = tps80031_regulator_probe, - .remove = tps80031_regulator_remove, }; static int __init tps80031_regulator_init(void) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 78aae4cbb00..8ebd785485c 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1188,7 +1188,7 @@ static int twlreg_probe(struct platform_device *pdev) config.driver_data = info; config.of_node = pdev->dev.of_node; - rdev = regulator_register(&info->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register %s, %ld\n", info->desc.name, PTR_ERR(rdev)); @@ -1217,7 +1217,6 @@ static int twlreg_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct twlreg_info *info = rdev->reg_data; - regulator_unregister(rdev); kfree(info); return 0; } diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c index 4668c7f8133..f3ae28a7e66 100644 --- a/drivers/regulator/vexpress.c +++ b/drivers/regulator/vexpress.c @@ -96,7 +96,7 @@ static int vexpress_regulator_probe(struct platform_device *pdev) config.driver_data = reg; config.of_node = pdev->dev.of_node; - reg->regdev = regulator_register(®->desc, &config); + reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config); if (IS_ERR(reg->regdev)) { err = PTR_ERR(reg->regdev); goto error_regulator_register; @@ -119,7 +119,6 @@ static int vexpress_regulator_remove(struct platform_device *pdev) struct vexpress_regulator *reg = platform_get_drvdata(pdev); vexpress_config_func_put(reg->func); - regulator_unregister(reg->regdev); return 0; } diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 11861cb861d..6823e6f2b88 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -387,8 +387,9 @@ static struct regulator_ops wm831x_buckv_ops = { * Set up DVS control. We just log errors since we can still run * (with reduced performance) if we fail. */ -static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, - struct wm831x_buckv_pdata *pdata) +static void wm831x_buckv_dvs_init(struct platform_device *pdev, + struct wm831x_dcdc *dcdc, + struct wm831x_buckv_pdata *pdata) { struct wm831x *wm831x = dcdc->wm831x; int ret; @@ -402,9 +403,9 @@ static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, */ dcdc->dvs_gpio_state = pdata->dvs_init_state; - ret = gpio_request_one(pdata->dvs_gpio, - dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, - "DCDC DVS"); + ret = devm_gpio_request_one(&pdev->dev, pdata->dvs_gpio, + dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, + "DCDC DVS"); if (ret < 0) { dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", dcdc->name, ret); @@ -513,7 +514,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev) dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK; if (pdata && pdata->dcdc[id]) - wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data); + wm831x_buckv_dvs_init(pdev, dcdc, + pdata->dcdc[id]->driver_data); config.dev = pdev->dev.parent; if (pdata) @@ -521,7 +523,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev) config.driver_data = dcdc; config.regmap = wm831x->regmap; - dcdc->regulator = regulator_register(&dcdc->desc, &config); + dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, + &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -530,57 +533,35 @@ static int wm831x_buckv_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); - ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, dcdc); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC")); - ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq, - IRQF_TRIGGER_RISING, dcdc->name, dcdc); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_dcdc_oc_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n", irq, ret); - goto err_uv; + goto err; } platform_set_drvdata(pdev, dcdc); return 0; -err_uv: - free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")), - dcdc); -err_regulator: - regulator_unregister(dcdc->regulator); err: - if (dcdc->dvs_gpio) - gpio_free(dcdc->dvs_gpio); return ret; } -static int wm831x_buckv_remove(struct platform_device *pdev) -{ - struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - struct wm831x *wm831x = dcdc->wm831x; - - free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC")), - dcdc); - free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")), - dcdc); - regulator_unregister(dcdc->regulator); - if (dcdc->dvs_gpio) - gpio_free(dcdc->dvs_gpio); - - return 0; -} - static struct platform_driver wm831x_buckv_driver = { .probe = wm831x_buckv_probe, - .remove = wm831x_buckv_remove, .driver = { .name = "wm831x-buckv", .owner = THIS_MODULE, @@ -681,7 +662,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev) config.driver_data = dcdc; config.regmap = wm831x->regmap; - dcdc->regulator = regulator_register(&dcdc->desc, &config); + dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, + &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -690,38 +672,25 @@ static int wm831x_buckp_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); - ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, dcdc); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } platform_set_drvdata(pdev, dcdc); return 0; -err_regulator: - regulator_unregister(dcdc->regulator); err: return ret; } -static int wm831x_buckp_remove(struct platform_device *pdev) -{ - struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - - free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")), - dcdc); - regulator_unregister(dcdc->regulator); - - return 0; -} - static struct platform_driver wm831x_buckp_driver = { .probe = wm831x_buckp_probe, - .remove = wm831x_buckp_remove, .driver = { .name = "wm831x-buckp", .owner = THIS_MODULE, @@ -813,7 +782,8 @@ static int wm831x_boostp_probe(struct platform_device *pdev) config.driver_data = dcdc; config.regmap = wm831x->regmap; - dcdc->regulator = regulator_register(&dcdc->desc, &config); + dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, + &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -822,39 +792,26 @@ static int wm831x_boostp_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); - ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, - dcdc); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, + dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } platform_set_drvdata(pdev, dcdc); return 0; -err_regulator: - regulator_unregister(dcdc->regulator); err: return ret; } -static int wm831x_boostp_remove(struct platform_device *pdev) -{ - struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - - free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")), - dcdc); - regulator_unregister(dcdc->regulator); - - return 0; -} - static struct platform_driver wm831x_boostp_driver = { .probe = wm831x_boostp_probe, - .remove = wm831x_boostp_remove, .driver = { .name = "wm831x-boostp", .owner = THIS_MODULE, @@ -914,7 +871,8 @@ static int wm831x_epe_probe(struct platform_device *pdev) config.driver_data = dcdc; config.regmap = wm831x->regmap; - dcdc->regulator = regulator_register(&dcdc->desc, &config); + dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, + &config); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register EPE%d: %d\n", @@ -930,18 +888,8 @@ err: return ret; } -static int wm831x_epe_remove(struct platform_device *pdev) -{ - struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - - regulator_unregister(dcdc->regulator); - - return 0; -} - static struct platform_driver wm831x_epe_driver = { .probe = wm831x_epe_probe, - .remove = wm831x_epe_remove, .driver = { .name = "wm831x-epe", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 4eb373de1fa..0339b886df5 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -194,7 +194,8 @@ static int wm831x_isink_probe(struct platform_device *pdev) config.init_data = pdata->isink[id]; config.driver_data = isink; - isink->regulator = regulator_register(&isink->desc, &config); + isink->regulator = devm_regulator_register(&pdev->dev, &isink->desc, + &config); if (IS_ERR(isink->regulator)) { ret = PTR_ERR(isink->regulator); dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n", @@ -203,38 +204,26 @@ static int wm831x_isink_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0)); - ret = request_threaded_irq(irq, NULL, wm831x_isink_irq, - IRQF_TRIGGER_RISING, isink->name, isink); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_isink_irq, + IRQF_TRIGGER_RISING, isink->name, + isink); if (ret != 0) { dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } platform_set_drvdata(pdev, isink); return 0; -err_regulator: - regulator_unregister(isink->regulator); err: return ret; } -static int wm831x_isink_remove(struct platform_device *pdev) -{ - struct wm831x_isink *isink = platform_get_drvdata(pdev); - - free_irq(wm831x_irq(isink->wm831x, platform_get_irq(pdev, 0)), isink); - - regulator_unregister(isink->regulator); - - return 0; -} - static struct platform_driver wm831x_isink_driver = { .probe = wm831x_isink_probe, - .remove = wm831x_isink_remove, .driver = { .name = "wm831x-isink", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 2205fbc2c37..46d6700467b 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -63,10 +63,8 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) */ static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), + REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000), }; static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -279,7 +277,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm831x->regmap; - ldo->regulator = regulator_register(&ldo->desc, &config); + ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, + &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -288,39 +287,26 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); - ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, - IRQF_TRIGGER_RISING, ldo->name, - ldo); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_ldo_uv_irq, + IRQF_TRIGGER_RISING, ldo->name, + ldo); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } platform_set_drvdata(pdev, ldo); return 0; -err_regulator: - regulator_unregister(ldo->regulator); err: return ret; } -static int wm831x_gp_ldo_remove(struct platform_device *pdev) -{ - struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - - free_irq(wm831x_irq(ldo->wm831x, - platform_get_irq_byname(pdev, "UV")), ldo); - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver wm831x_gp_ldo_driver = { .probe = wm831x_gp_ldo_probe, - .remove = wm831x_gp_ldo_remove, .driver = { .name = "wm831x-ldo", .owner = THIS_MODULE, @@ -332,10 +318,8 @@ static struct platform_driver wm831x_gp_ldo_driver = { */ static const struct regulator_linear_range wm831x_aldo_ranges[] = { - { .min_uV = 1000000, .max_uV = 1600000, .min_sel = 0, .max_sel = 12, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(1000000, 0, 12, 50000), + REGULATOR_LINEAR_RANGE(1700000, 13, 31, 100000), }; static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -505,7 +489,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm831x->regmap; - ldo->regulator = regulator_register(&ldo->desc, &config); + ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, + &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -514,38 +499,25 @@ static int wm831x_aldo_probe(struct platform_device *pdev) } irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); - ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, - IRQF_TRIGGER_RISING, ldo->name, ldo); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + wm831x_ldo_uv_irq, + IRQF_TRIGGER_RISING, ldo->name, ldo); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); - goto err_regulator; + goto err; } platform_set_drvdata(pdev, ldo); return 0; -err_regulator: - regulator_unregister(ldo->regulator); err: return ret; } -static int wm831x_aldo_remove(struct platform_device *pdev) -{ - struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - - free_irq(wm831x_irq(ldo->wm831x, platform_get_irq_byname(pdev, "UV")), - ldo); - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver wm831x_aldo_driver = { .probe = wm831x_aldo_probe, - .remove = wm831x_aldo_remove, .driver = { .name = "wm831x-aldo", .owner = THIS_MODULE, @@ -663,7 +635,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm831x->regmap; - ldo->regulator = regulator_register(&ldo->desc, &config); + ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, + &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -679,18 +652,8 @@ err: return ret; } -static int wm831x_alive_ldo_remove(struct platform_device *pdev) -{ - struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver wm831x_alive_ldo_driver = { .probe = wm831x_alive_ldo_probe, - .remove = wm831x_alive_ldo_remove, .driver = { .name = "wm831x-alive-ldo", .owner = THIS_MODULE, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 61ca9292a42..de7b9c73e3f 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -543,10 +543,8 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, } static const struct regulator_linear_range wm8350_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 15, - .uV_step = 50000 }, - { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 15, 50000), + REGULATOR_LINEAR_RANGE(1800000, 16, 31, 100000), }; static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -1206,7 +1204,8 @@ static int wm8350_regulator_probe(struct platform_device *pdev) config.regmap = wm8350->regmap; /* register regulator */ - rdev = regulator_register(&wm8350_reg[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, &wm8350_reg[pdev->id], + &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", wm8350_reg[pdev->id].name); @@ -1217,7 +1216,6 @@ static int wm8350_regulator_probe(struct platform_device *pdev) ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq, pmic_uv_handler, 0, "UV", rdev); if (ret < 0) { - regulator_unregister(rdev); dev_err(&pdev->dev, "failed to register regulator %s IRQ\n", wm8350_reg[pdev->id].name); return ret; @@ -1233,8 +1231,6 @@ static int wm8350_regulator_remove(struct platform_device *pdev) wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev); - regulator_unregister(rdev); - return 0; } diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 58f51bec13f..82d82900085 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -20,10 +20,8 @@ #include <linux/mfd/wm8400-private.h> static const struct regulator_linear_range wm8400_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), + REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000), }; static struct regulator_ops wm8400_ldo_ops = { @@ -219,7 +217,8 @@ static int wm8400_regulator_probe(struct platform_device *pdev) config.driver_data = wm8400; config.regmap = wm8400->regmap; - rdev = regulator_register(®ulators[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, ®ulators[pdev->id], + &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -228,21 +227,11 @@ static int wm8400_regulator_probe(struct platform_device *pdev) return 0; } -static int wm8400_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver wm8400_regulator_driver = { .driver = { .name = "wm8400-regulator", }, .probe = wm8400_regulator_probe, - .remove = wm8400_regulator_remove, }; /** diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 5ee2a208457..71c5911f2e7 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -165,7 +165,9 @@ static int wm8994_ldo_probe(struct platform_device *pdev) ldo->init_data = *pdata->ldo[id].init_data; } - ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config); + ldo->regulator = devm_regulator_register(&pdev->dev, + &wm8994_ldo_desc[id], + &config); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", @@ -181,18 +183,8 @@ err: return ret; } -static int wm8994_ldo_remove(struct platform_device *pdev) -{ - struct wm8994_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver wm8994_ldo_driver = { .probe = wm8994_ldo_probe, - .remove = wm8994_ldo_remove, .driver = { .name = "wm8994-ldo", .owner = THIS_MODULE, diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 72c5cdbe079..544be722937 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -72,6 +72,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) } else err = -EINVAL; + pm_stay_awake(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); /* A timer might have just expired */ schedule_work(&rtc->irqwork); @@ -113,6 +114,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = -EINVAL; } + pm_stay_awake(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); /* A timer might have just expired */ schedule_work(&rtc->irqwork); @@ -771,9 +773,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); - else if (err) { + } else if (err) { timerqueue_del(&rtc->timerqueue, &timer->node); timer->enabled = 0; return err; @@ -818,8 +821,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); + } } } @@ -845,7 +850,6 @@ void rtc_timer_do_work(struct work_struct *work) mutex_lock(&rtc->ops_lock); again: - pm_relax(rtc->dev.parent); __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); while ((next = timerqueue_getnext(&rtc->timerqueue))) { @@ -880,6 +884,7 @@ again: } else rtc_alarm_disable(rtc); + pm_relax(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); } diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 9c8f6090379..dc4f14255cc 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -14,7 +14,9 @@ #include <linux/module.h> #include <linux/rtc.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/io.h> #include <linux/slab.h> diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 578baf9d972..315209d9b40 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -38,8 +38,8 @@ #include <asm-generic/rtc.h> #include <asm/intel_scu_ipc.h> -#include <asm/mrst.h> -#include <asm/mrst-vrtc.h> +#include <asm/intel-mid.h> +#include <asm/intel_mid_vrtc.h> struct mrst_rtc { struct rtc_device *rtc; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 0f0609b1aa2..e3b25712b65 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -371,6 +371,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) } } + device_init_wakeup(&adev->dev, 1); ldata->rtc = rtc_device_register("pl031", &adev->dev, ops, THIS_MODULE); if (IS_ERR(ldata->rtc)) { @@ -384,8 +385,6 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_irq; } - device_init_wakeup(&adev->dev, 1); - return 0; out_no_irq: diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index b9c53cc40e1..eb1f1ef5fa2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -264,6 +264,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select SPI_BITBANG + depends on SOC_VF610 || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. @@ -369,7 +370,7 @@ config SPI_PXA2XX_PCI config SPI_RSPI tristate "Renesas RSPI controller" - depends on SUPERH && SH_DMAE_BASE + depends on (SUPERH || ARCH_SHMOBILE) && SH_DMAE_BASE help SPI driver for Renesas RSPI blocks. @@ -393,7 +394,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on (ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS) + depends on PLAT_SAMSUNG select S3C64XX_DMA if ARCH_S3C64XX help SPI driver for Samsung S3C64XX and newer SoCs. diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 9a64c3fee21..595b62cb545 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -219,7 +219,7 @@ static int altera_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hw); /* setup the state for the bitbang driver */ - hw->bitbang.master = spi_master_get(master); + hw->bitbang.master = master; if (!hw->bitbang.master) return err; hw->bitbang.chipselect = altera_spi_chipsel; diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 37bad952ab3..821bf7ac218 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -231,7 +231,7 @@ static int ath79_spi_probe(struct platform_device *pdev) master->num_chipselect = pdata->num_chipselect; } - sp->bitbang.master = spi_master_get(master); + sp->bitbang.master = master; sp->bitbang.chipselect = ath79_spi_chipselect; sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0; sp->bitbang.setup_transfer = spi_bitbang_setup_transfer; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index d4ac60b4a56..273db0beb2b 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -170,18 +170,18 @@ /* Bit manipulation macros */ #define SPI_BIT(name) \ (1 << SPI_##name##_OFFSET) -#define SPI_BF(name,value) \ +#define SPI_BF(name, value) \ (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET) -#define SPI_BFEXT(name,value) \ +#define SPI_BFEXT(name, value) \ (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1)) -#define SPI_BFINS(name,value,old) \ - ( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ - | SPI_BF(name,value)) +#define SPI_BFINS(name, value, old) \ + (((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ + | SPI_BF(name, value)) /* Register access macros */ -#define spi_readl(port,reg) \ +#define spi_readl(port, reg) \ __raw_readl((port)->regs + SPI_##reg) -#define spi_writel(port,reg,value) \ +#define spi_writel(port, reg, value) \ __raw_writel((value), (port)->regs + SPI_##reg) /* use PIO for small transfers, avoiding DMA setup/teardown overhead and @@ -1401,8 +1401,8 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) asd = spi->controller_state; bits = (asd->csr >> 4) & 0xf; if (bits != xfer->bits_per_word - 8) { - dev_dbg(&spi->dev, "you can't yet change " - "bits_per_word in transfers\n"); + dev_dbg(&spi->dev, + "you can't yet change bits_per_word in transfers\n"); return -ENOPROTOOPT; } } @@ -1516,7 +1516,7 @@ static int atmel_spi_probe(struct platform_device *pdev) /* setup spi core then atmel-specific driver state */ ret = -ENOMEM; - master = spi_alloc_master(&pdev->dev, sizeof *as); + master = spi_alloc_master(&pdev->dev, sizeof(*as)); if (!master) goto out_free; @@ -1546,9 +1546,11 @@ static int atmel_spi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&as->queue); as->pdev = pdev; - as->regs = ioremap(regs->start, resource_size(regs)); - if (!as->regs) + as->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(as->regs)) { + ret = PTR_ERR(as->regs); goto out_free_buffer; + } as->phybase = regs->start; as->irq = irq; as->clk = clk; @@ -1617,7 +1619,6 @@ out_free_dma: out_free_irq: free_irq(irq, master); out_unmap_regs: - iounmap(as->regs); out_free_buffer: if (!as->use_pdc) tasklet_kill(&as->tasklet); @@ -1669,36 +1670,36 @@ static int atmel_spi_remove(struct platform_device *pdev) clk_disable_unprepare(as->clk); clk_put(as->clk); free_irq(as->irq, master); - iounmap(as->regs); spi_unregister_master(master); return 0; } -#ifdef CONFIG_PM - -static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int atmel_spi_suspend(struct device *dev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct atmel_spi *as = spi_master_get_devdata(master); clk_disable_unprepare(as->clk); return 0; } -static int atmel_spi_resume(struct platform_device *pdev) +static int atmel_spi_resume(struct device *dev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct atmel_spi *as = spi_master_get_devdata(master); - return clk_prepare_enable(as->clk); + clk_prepare_enable(as->clk); return 0; } +static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume); + +#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops) #else -#define atmel_spi_suspend NULL -#define atmel_spi_resume NULL +#define ATMEL_SPI_PM_OPS NULL #endif #if defined(CONFIG_OF) @@ -1714,10 +1715,9 @@ static struct platform_driver atmel_spi_driver = { .driver = { .name = "atmel_spi", .owner = THIS_MODULE, + .pm = ATMEL_SPI_PM_OPS, .of_match_table = of_match_ptr(atmel_spi_dt_ids), }, - .suspend = atmel_spi_suspend, - .resume = atmel_spi_resume, .probe = atmel_spi_probe, .remove = atmel_spi_remove, }; diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 1d00d9b397d..c4141c92bcf 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -775,7 +775,7 @@ static int au1550_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); - hw->master = spi_master_get(master); + hw->master = master; hw->pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; @@ -985,6 +985,7 @@ static int au1550_spi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:au1550-spi"); static struct platform_driver au1550_spi_drv = { + .probe = au1550_spi_probe, .remove = au1550_spi_remove, .driver = { .name = "au1550-spi", @@ -1004,7 +1005,7 @@ static int __init au1550_spi_init(void) printk(KERN_ERR "au1550-spi: cannot add memory" "dbdma device\n"); } - return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe); + return platform_driver_register(&au1550_spi_drv); } module_init(au1550_spi_init); diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 52c81481c5c..4c332143a31 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -358,7 +358,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); - err = spi_register_master(master); + err = devm_spi_register_master(&pdev->dev, master); if (err) { dev_err(&pdev->dev, "could not register SPI master: %d\n", err); goto out_free_irq; @@ -381,14 +381,12 @@ static int bcm2835_spi_remove(struct platform_device *pdev) struct bcm2835_spi *bs = spi_master_get_devdata(master); free_irq(bs->irq, master); - spi_unregister_master(master); /* Clear FIFOs, and disable the HW block */ bcm2835_wr(bs, BCM2835_SPI_CS, BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); clk_disable_unprepare(bs->clk); - spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 536b0e36382..80d56b214eb 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -412,7 +412,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); /* register and we are done */ - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret) { dev_err(dev, "spi register failed\n"); goto out_clk_disable; @@ -438,8 +438,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev) struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct bcm63xx_spi *bs = spi_master_get_devdata(master); - spi_unregister_master(master); - /* reset spi block */ bcm_spi_writeb(bs, 0, SPI_INT_MASK); @@ -447,8 +445,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev) clk_disable_unprepare(bs->clk); clk_put(bs->clk); - spi_master_put(master); - return 0; } diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 91921b5f581..38941e5920b 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -592,7 +592,7 @@ bfin_sport_spi_setup(struct spi_device *spi) */ if (chip_info->ctl_reg || chip_info->enable_dma) { ret = -EINVAL; - dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields"); + dev_err(&spi->dev, "don't set ctl_reg/enable_dma fields\n"); goto error; } chip->cs_chg_udelay = chip_info->cs_chg_udelay; @@ -879,11 +879,10 @@ static int bfin_sport_spi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int -bfin_sport_spi_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int bfin_sport_spi_suspend(struct device *dev) { - struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev); int status; status = bfin_sport_spi_stop_queue(drv_data); @@ -896,10 +895,9 @@ bfin_sport_spi_suspend(struct platform_device *pdev, pm_message_t state) return status; } -static int -bfin_sport_spi_resume(struct platform_device *pdev) +static int bfin_sport_spi_resume(struct device *dev) { - struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_sport_spi_master_data *drv_data = dev_get_drvdata(dev); int status; /* Enable the SPI interface */ @@ -912,19 +910,22 @@ bfin_sport_spi_resume(struct platform_device *pdev) return status; } + +static SIMPLE_DEV_PM_OPS(bfin_sport_spi_pm_ops, bfin_sport_spi_suspend, + bfin_sport_spi_resume); + +#define BFIN_SPORT_SPI_PM_OPS (&bfin_sport_spi_pm_ops) #else -# define bfin_sport_spi_suspend NULL -# define bfin_sport_spi_resume NULL +#define BFIN_SPORT_SPI_PM_OPS NULL #endif static struct platform_driver bfin_sport_spi_driver = { .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = BFIN_SPORT_SPI_PM_OPS, }, .probe = bfin_sport_spi_probe, .remove = bfin_sport_spi_remove, - .suspend = bfin_sport_spi_suspend, - .resume = bfin_sport_spi_resume, }; module_platform_driver(bfin_sport_spi_driver); diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c index f4bf81347d6..8f8598834b3 100644 --- a/drivers/spi/spi-bfin-v3.c +++ b/drivers/spi/spi-bfin-v3.c @@ -867,7 +867,7 @@ static int bfin_spi_probe(struct platform_device *pdev) tasklet_init(&drv_data->pump_transfers, bfin_spi_pump_transfers, (unsigned long)drv_data); /* register with the SPI framework */ - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret) { dev_err(dev, "can not register spi master\n"); goto err_free_peripheral; @@ -898,7 +898,6 @@ static int bfin_spi_remove(struct platform_device *pdev) free_dma(drv_data->rx_dma); free_dma(drv_data->tx_dma); - spi_unregister_master(drv_data->master); return 0; } diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index 45bdf73d686..f0f195af75d 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -524,7 +524,7 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id) timeout = jiffies + HZ; while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF)) if (!time_before(jiffies, timeout)) { - dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF"); + dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF\n"); break; } else cpu_relax(); @@ -913,8 +913,9 @@ static void bfin_spi_pump_messages(struct work_struct *work) drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, struct spi_transfer, transfer_list); - dev_dbg(&drv_data->pdev->dev, "got a message to pump, " - "state is set to: baud %d, flag 0x%x, ctl 0x%x\n", + dev_dbg(&drv_data->pdev->dev, + "got a message to pump, state is set to: baud " + "%d, flag 0x%x, ctl 0x%x\n", drv_data->cur_chip->baud, drv_data->cur_chip->flag, drv_data->cur_chip->ctl_reg); @@ -1013,8 +1014,8 @@ static int bfin_spi_setup(struct spi_device *spi) * but let's assume (for now) they do. */ if (chip_info->ctl_reg & ~bfin_ctl_reg) { - dev_err(&spi->dev, "do not set bits in ctl_reg " - "that the SPI framework manages\n"); + dev_err(&spi->dev, + "do not set bits in ctl_reg that the SPI framework manages\n"); goto error; } chip->enable_dma = chip_info->enable_dma != 0 @@ -1050,17 +1051,17 @@ static int bfin_spi_setup(struct spi_device *spi) chip->chip_select_num = spi->chip_select; if (chip->chip_select_num < MAX_CTRL_CS) { if (!(spi->mode & SPI_CPHA)) - dev_warn(&spi->dev, "Warning: SPI CPHA not set:" - " Slave Select not under software control!\n" - " See Documentation/blackfin/bfin-spi-notes.txt"); + dev_warn(&spi->dev, + "Warning: SPI CPHA not set: Slave Select not under software control!\n" + "See Documentation/blackfin/bfin-spi-notes.txt\n"); chip->flag = (1 << spi->chip_select) << 8; } else chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS; if (chip->enable_dma && chip->pio_interrupt) { - dev_err(&spi->dev, "enable_dma is set, " - "do not set pio_interrupt\n"); + dev_err(&spi->dev, + "enable_dma is set, do not set pio_interrupt\n"); goto error; } /* @@ -1410,10 +1411,10 @@ static int bfin_spi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int bfin_spi_suspend(struct device *dev) { - struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev); int status = 0; status = bfin_spi_stop_queue(drv_data); @@ -1432,9 +1433,9 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int bfin_spi_resume(struct platform_device *pdev) +static int bfin_spi_resume(struct device *dev) { - struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev); + struct bfin_spi_master_data *drv_data = dev_get_drvdata(dev); int status = 0; bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg); @@ -1443,31 +1444,34 @@ static int bfin_spi_resume(struct platform_device *pdev) /* Start the queue running */ status = bfin_spi_start_queue(drv_data); if (status != 0) { - dev_err(&pdev->dev, "problem starting queue (%d)\n", status); + dev_err(dev, "problem starting queue (%d)\n", status); return status; } return 0; } + +static SIMPLE_DEV_PM_OPS(bfin_spi_pm_ops, bfin_spi_suspend, bfin_spi_resume); + +#define BFIN_SPI_PM_OPS (&bfin_spi_pm_ops) #else -#define bfin_spi_suspend NULL -#define bfin_spi_resume NULL -#endif /* CONFIG_PM */ +#define BFIN_SPI_PM_OPS NULL +#endif MODULE_ALIAS("platform:bfin-spi"); static struct platform_driver bfin_spi_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .pm = BFIN_SPI_PM_OPS, }, - .suspend = bfin_spi_suspend, - .resume = bfin_spi_resume, + .probe = bfin_spi_probe, .remove = bfin_spi_remove, }; static int __init bfin_spi_init(void) { - return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe); + return platform_driver_register(&bfin_spi_driver); } subsys_initcall(bfin_spi_init); diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 8c11355dec2..bd222f6b677 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -191,7 +191,7 @@ int spi_bitbang_setup(struct spi_device *spi) bitbang = spi_master_get_devdata(spi->master); if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; @@ -258,7 +258,7 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) static int spi_bitbang_prepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang; + struct spi_bitbang *bitbang; unsigned long flags; bitbang = spi_master_get_devdata(spi); @@ -273,7 +273,7 @@ static int spi_bitbang_prepare_hardware(struct spi_master *spi) static int spi_bitbang_transfer_one(struct spi_master *master, struct spi_message *m) { - struct spi_bitbang *bitbang; + struct spi_bitbang *bitbang; unsigned nsecs; struct spi_transfer *t = NULL; unsigned cs_change; @@ -292,7 +292,7 @@ static int spi_bitbang_transfer_one(struct spi_master *master, cs_change = 1; status = 0; - list_for_each_entry (t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) { /* override speed or wordsize? */ if (t->speed_hz || t->bits_per_word) @@ -349,7 +349,8 @@ static int spi_bitbang_transfer_one(struct spi_master *master, if (t->delay_usecs) udelay(t->delay_usecs); - if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { + if (cs_change && + !list_is_last(&t->transfer_list, &m->transfers)) { /* sometimes a short mid-message deselect of the chip * may be needed to terminate a mode or command */ @@ -378,7 +379,7 @@ static int spi_bitbang_transfer_one(struct spi_master *master, static int spi_bitbang_unprepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang; + struct spi_bitbang *bitbang; unsigned long flags; bitbang = spi_master_get_devdata(spi); @@ -414,10 +415,16 @@ static int spi_bitbang_unprepare_hardware(struct spi_master *spi) * This routine registers the spi_master, which will process requests in a * dedicated task, keeping IRQs unblocked most of the time. To stop * processing those requests, call spi_bitbang_stop(). + * + * On success, this routine will take a reference to master. The caller is + * responsible for calling spi_bitbang_stop() to decrement the reference and + * spi_master_put() as counterpart of spi_alloc_master() to prevent a memory + * leak. */ int spi_bitbang_start(struct spi_bitbang *bitbang) { struct spi_master *master = bitbang->master; + int ret; if (!master || !bitbang->chipselect) return -EINVAL; @@ -449,7 +456,11 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* driver may get busy before register() returns, especially * if someone registered boardinfo for devices */ - return spi_register_master(master); + ret = spi_register_master(spi_master_get(master)); + if (ret) + spi_master_put(master); + + return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_start); diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 5ed08e53743..8081f96bd1d 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -147,8 +147,8 @@ static void butterfly_chipselect(struct spi_device *spi, int value) /* we only needed to implement one mode here, and choose SPI_MODE_0 */ -#define spidelay(X) do{}while(0) -//#define spidelay ndelay +#define spidelay(X) do { } while (0) +/* #define spidelay ndelay */ #include "spi-bitbang-txrx.h" @@ -171,15 +171,15 @@ static struct mtd_partition partitions[] = { { /* sector 0 = 8 pages * 264 bytes/page (1 block) * sector 1 = 248 pages * 264 bytes/page */ - .name = "bookkeeping", // 66 KB + .name = "bookkeeping", /* 66 KB */ .offset = 0, .size = (8 + 248) * 264, -// .mask_flags = MTD_WRITEABLE, + /* .mask_flags = MTD_WRITEABLE, */ }, { /* sector 2 = 256 pages * 264 bytes/page * sectors 3-5 = 512 pages * 264 bytes/page */ - .name = "filesystem", // 462 KB + .name = "filesystem", /* 462 KB */ .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, } }; @@ -209,7 +209,7 @@ static void butterfly_attach(struct parport *p) * and no way to be selective about what it binds to. */ - master = spi_alloc_master(dev, sizeof *pp); + master = spi_alloc_master(dev, sizeof(*pp)); if (!master) { status = -ENOMEM; goto done; @@ -225,7 +225,7 @@ static void butterfly_attach(struct parport *p) master->bus_num = 42; master->num_chipselect = 2; - pp->bitbang.master = spi_master_get(master); + pp->bitbang.master = master; pp->bitbang.chipselect = butterfly_chipselect; pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0; @@ -289,7 +289,6 @@ static void butterfly_attach(struct parport *p) pr_debug("%s: dataflash at %s\n", p->name, dev_name(&pp->dataflash->dev)); - // dev_info(_what?_, ...) pr_info("%s: AVR Butterfly\n", p->name); butterfly = pp; return; diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 6416798828e..e2a5a426b2e 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -226,10 +226,10 @@ static int spi_clps711x_probe(struct platform_device *pdev) dev_name(&pdev->dev), hw); if (ret) { dev_err(&pdev->dev, "Can't request IRQ\n"); - goto clk_out; + goto err_out; } - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (!ret) { dev_info(&pdev->dev, "SPI bus driver initialized. Master clock %u Hz\n", @@ -239,7 +239,6 @@ static int spi_clps711x_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to register master\n"); -clk_out: err_out: while (--i >= 0) if (gpio_is_valid(hw->chipselect[i])) @@ -260,8 +259,6 @@ static int spi_clps711x_remove(struct platform_device *pdev) if (gpio_is_valid(hw->chipselect[i])) gpio_free(hw->chipselect[i]); - spi_unregister_master(master); - return 0; } diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 8fbfe2483ff..dd72445ba2e 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -279,7 +279,8 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, struct davinci_spi *dspi; struct davinci_spi_config *spicfg; u8 bits_per_word = 0; - u32 hz = 0, spifmt = 0, prescale = 0; + u32 hz = 0, spifmt = 0; + int prescale; dspi = spi_master_get_devdata(spi->master); spicfg = (struct davinci_spi_config *)spi->controller_data; @@ -916,7 +917,7 @@ static int davinci_spi_probe(struct platform_device *pdev) if (ret) goto unmap_io; - dspi->bitbang.master = spi_master_get(master); + dspi->bitbang.master = master; if (dspi->bitbang.master == NULL) { ret = -ENODEV; goto irq_free; @@ -925,7 +926,7 @@ static int davinci_spi_probe(struct platform_device *pdev) dspi->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dspi->clk)) { ret = -ENODEV; - goto put_master; + goto irq_free; } clk_prepare_enable(dspi->clk); @@ -1015,8 +1016,6 @@ free_dma: free_clk: clk_disable_unprepare(dspi->clk); clk_put(dspi->clk); -put_master: - spi_master_put(master); irq_free: free_irq(dspi->irq, dspi); unmap_io: @@ -1024,7 +1023,7 @@ unmap_io: release_region: release_mem_region(dspi->pbase, resource_size(r)); free_master: - kfree(master); + spi_master_put(master); err: return ret; } @@ -1051,11 +1050,11 @@ static int davinci_spi_remove(struct platform_device *pdev) clk_disable_unprepare(dspi->clk); clk_put(dspi->clk); - spi_master_put(master); free_irq(dspi->irq, dspi); iounmap(dspi->base); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(dspi->pbase, resource_size(r)); + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 4aa8be865cc..168c620947f 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -74,7 +74,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dwsmmio->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dwsmmio->clk)) { ret = PTR_ERR(dwsmmio->clk); - goto err_irq; + goto err_unmap; } clk_enable(dwsmmio->clk); @@ -94,8 +94,6 @@ err_clk: clk_disable(dwsmmio->clk); clk_put(dwsmmio->clk); dwsmmio->clk = NULL; -err_irq: - free_irq(dws->irq, dws); err_unmap: iounmap(dws->regs); err_release_reg: @@ -115,7 +113,6 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) clk_put(dwsmmio->clk); dwsmmio->clk = NULL; - free_irq(dwsmmio->dws.irq, &dwsmmio->dws); dw_spi_remove_host(&dwsmmio->dws); iounmap(dwsmmio->dws.regs); kfree(dwsmmio); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 6055c8d9fdd..66fa9955ea1 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -40,7 +40,7 @@ static int spi_pci_probe(struct pci_dev *pdev, int pci_bar = 0; int ret; - printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n", + dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", pdev->vendor, pdev->device); ret = pci_enable_device(pdev); @@ -109,7 +109,6 @@ static void spi_pci_remove(struct pci_dev *pdev) { struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); - pci_set_drvdata(pdev, NULL); dw_spi_remove_host(&dwpci->dws); iounmap(dwpci->dws.regs); pci_release_region(pdev, 0); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 79c958e49f6..b897c4adb39 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -870,8 +870,8 @@ void dw_spi_remove_host(struct dw_spi *dws) /* Remove the queue */ status = destroy_queue(dws); if (status != 0) - dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not " - "complete, message memory not freed\n"); + dev_err(&dws->master->dev, + "dw_spi_remove: workqueue will not complete, message memory not freed\n"); if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index 7d84418a01d..d4d3cc53479 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -280,10 +280,6 @@ static irqreturn_t efm32_spi_txirq(int irq, void *data) return IRQ_HANDLED; } -static const struct efm32_spi_pdata efm32_spi_pdata_default = { - .location = 1, -}; - static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata) { u32 reg = efm32_spi_read32(ddata, REG_ROUTE); @@ -347,7 +343,7 @@ static int efm32_spi_probe(struct platform_device *pdev) ddata = spi_master_get_devdata(master); - ddata->bitbang.master = spi_master_get(master); + ddata->bitbang.master = master; ddata->bitbang.chipselect = efm32_spi_chipselect; ddata->bitbang.setup_transfer = efm32_spi_setup_transfer; ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; @@ -387,7 +383,7 @@ static int efm32_spi_probe(struct platform_device *pdev) goto err; } - if (resource_size(res) < 60) { + if (resource_size(res) < 0x60) { ret = -EINVAL; dev_err(&pdev->dev, "memory resource too small\n"); goto err; @@ -467,7 +463,6 @@ err_disable_clk: clk_disable_unprepare(ddata->clk); err: spi_master_put(master); - kfree(master); } return ret; @@ -478,13 +473,14 @@ static int efm32_spi_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct efm32_spi_ddata *ddata = spi_master_get_devdata(master); + spi_bitbang_stop(&ddata->bitbang); + efm32_spi_write32(ddata, 0, REG_IEN); free_irq(ddata->txirq, ddata); free_irq(ddata->rxirq, ddata); clk_disable_unprepare(ddata->clk); spi_master_put(master); - kfree(master); return 0; } diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index d22c00a227b..1bfaed6e407 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -330,7 +330,7 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", chip->spi->mode, div_cpsr, div_scr, dss); - dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0); + dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); ep93xx_spi_write_u16(espi, SSPCR0, cr0); @@ -509,7 +509,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) } if (WARN_ON(len)) { - dev_warn(&espi->pdev->dev, "len = %zu expected 0!", len); + dev_warn(&espi->pdev->dev, "len = %zu expected 0!\n", len); return ERR_PTR(-EINVAL); } @@ -942,7 +942,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev) /* make sure that the hardware is disabled */ ep93xx_spi_write_u8(espi, SSPCR1, 0); - error = spi_register_master(master); + error = devm_spi_register_master(&pdev->dev, master); if (error) { dev_err(&pdev->dev, "failed to register SPI master\n"); goto fail_free_dma; @@ -968,7 +968,6 @@ static int ep93xx_spi_remove(struct platform_device *pdev) ep93xx_spi_release_dma(espi); - spi_unregister_master(master); return 0; } diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 07971e3fe58..54b06376f03 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -20,6 +20,7 @@ #include <linux/spi/spi.h> #include <linux/fsl_devices.h> #include <linux/dma-mapping.h> +#include <linux/of_address.h> #include <asm/cpm.h> #include <asm/qe.h> @@ -299,7 +300,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) switch (mspi->subblock) { default: - dev_warn(dev, "cell-index unspecified, assuming SPI1"); + dev_warn(dev, "cell-index unspecified, assuming SPI1\n"); /* fall through */ case 0: mspi->subblock = QE_CR_SUBBLOCK_SPI1; diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 4e44575bd87..8641b03bdd7 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -108,7 +108,7 @@ struct fsl_dspi { struct spi_bitbang bitbang; struct platform_device *pdev; - void *base; + void __iomem *base; int irq; struct clk *clk; @@ -165,7 +165,7 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, } } - pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\ + pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\ ,we use the max prescaler value.\n", speed_hz, clkrate); *pbr = ARRAY_SIZE(pbr_tbl) - 1; *br = ARRAY_SIZE(brs) - 1; @@ -450,7 +450,7 @@ static int dspi_probe(struct platform_device *pdev) dspi = spi_master_get_devdata(master); dspi->pdev = pdev; - dspi->bitbang.master = spi_master_get(master); + dspi->bitbang.master = master; dspi->bitbang.chipselect = dspi_chipselect; dspi->bitbang.setup_transfer = dspi_setup_transfer; dspi->bitbang.txrx_bufs = dspi_txrx_transfer; @@ -520,7 +520,6 @@ out_clk_put: clk_disable_unprepare(dspi->clk); out_master_put: spi_master_put(master); - platform_set_drvdata(pdev, NULL); return ret; } @@ -531,6 +530,7 @@ static int dspi_remove(struct platform_device *pdev) /* Disconnect from the SPI framework */ spi_bitbang_stop(&dspi->bitbang); + clk_disable_unprepare(dspi->clk); spi_master_put(dspi->bitbang.master); return 0; @@ -547,5 +547,5 @@ static struct platform_driver fsl_dspi_driver = { module_platform_driver(fsl_dspi_driver); MODULE_DESCRIPTION("Freescale DSPI Controller Driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index b8f1103fe28..32200d4f878 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -16,6 +16,8 @@ #include <linux/fsl_devices.h> #include <linux/mm.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/interrupt.h> #include <linux/err.h> @@ -289,8 +291,8 @@ static void fsl_espi_do_trans(struct spi_message *m, if ((first->bits_per_word != t->bits_per_word) || (first->speed_hz != t->speed_hz)) { espi_trans->status = -EINVAL; - dev_err(mspi->dev, "bits_per_word/speed_hz should be" - " same for the same SPI transfer\n"); + dev_err(mspi->dev, + "bits_per_word/speed_hz should be same for the same SPI transfer\n"); return; } @@ -687,7 +689,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) struct device_node *np = ofdev->dev.of_node; struct spi_master *master; struct resource mem; - struct resource irq; + unsigned int irq; int ret = -ENOMEM; ret = of_mpc8xxx_spi_probe(ofdev); @@ -702,13 +704,13 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) if (ret) goto err; - ret = of_irq_to_resource(np, 0, &irq); + irq = irq_of_parse_and_map(np, 0); if (!ret) { ret = -EINVAL; goto err; } - master = fsl_espi_probe(dev, &mem, irq.start); + master = fsl_espi_probe(dev, &mem, irq); if (IS_ERR(master)) { ret = PTR_ERR(master); goto err; diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 68b69fec13a..3fb09f98198 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> @@ -467,7 +468,7 @@ static int spi_gpio_probe(struct platform_device *pdev) } #endif - spi_gpio->bitbang.master = spi_master_get(master); + spi_gpio->bitbang.master = master; spi_gpio->bitbang.chipselect = spi_gpio_chipselect; if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) { @@ -486,7 +487,6 @@ static int spi_gpio_probe(struct platform_device *pdev) status = spi_bitbang_start(&spi_gpio->bitbang); if (status < 0) { - spi_master_put(spi_gpio->bitbang.master); gpio_free: if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) gpio_free(SPI_MISO_GPIO); @@ -510,13 +510,13 @@ static int spi_gpio_remove(struct platform_device *pdev) /* stop() unregisters child devices too */ status = spi_bitbang_stop(&spi_gpio->bitbang); - spi_master_put(spi_gpio->bitbang.master); if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) gpio_free(SPI_MISO_GPIO); if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) gpio_free(SPI_MOSI_GPIO); gpio_free(SPI_SCK_GPIO); + spi_master_put(spi_gpio->bitbang.master); return status; } diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 15323d8bd9c..b80f2f70fef 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -749,6 +749,35 @@ static void spi_imx_cleanup(struct spi_device *spi) { } +static int +spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg) +{ + struct spi_imx_data *spi_imx = spi_master_get_devdata(master); + int ret; + + ret = clk_enable(spi_imx->clk_per); + if (ret) + return ret; + + ret = clk_enable(spi_imx->clk_ipg); + if (ret) { + clk_disable(spi_imx->clk_per); + return ret; + } + + return 0; +} + +static int +spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg) +{ + struct spi_imx_data *spi_imx = spi_master_get_devdata(master); + + clk_disable(spi_imx->clk_ipg); + clk_disable(spi_imx->clk_per); + return 0; +} + static int spi_imx_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -786,7 +815,7 @@ static int spi_imx_probe(struct platform_device *pdev) master->num_chipselect = num_cs; spi_imx = spi_master_get_devdata(master); - spi_imx->bitbang.master = spi_master_get(master); + spi_imx->bitbang.master = master; for (i = 0; i < master->num_chipselect; i++) { int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); @@ -810,6 +839,8 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.txrx_bufs = spi_imx_transfer; spi_imx->bitbang.master->setup = spi_imx_setup; spi_imx->bitbang.master->cleanup = spi_imx_cleanup; + spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; + spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; init_completion(&spi_imx->xfer_done); @@ -872,6 +903,8 @@ static int spi_imx_probe(struct platform_device *pdev) dev_info(&pdev->dev, "probed\n"); + clk_disable(spi_imx->clk_ipg); + clk_disable(spi_imx->clk_per); return ret; out_clk_put: diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 0759b5db988..41c5765be74 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -222,7 +222,7 @@ static void spi_lm70llp_attach(struct parport *p) /* * SPI and bitbang hookup. */ - pp->bitbang.master = spi_master_get(master); + pp->bitbang.master = master; pp->bitbang.chipselect = lm70_chipselect; pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx; pp->bitbang.flags = SPI_3WIRE; diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 6adf4e35816..58d5ee0e444 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -20,6 +20,7 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/completion.h> #include <linux/io.h> @@ -536,7 +537,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, if (ret < 0) goto free_clock; - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret < 0) goto free_clock; @@ -559,12 +560,10 @@ static int mpc512x_psc_spi_do_remove(struct device *dev) struct spi_master *master = spi_master_get(dev_get_drvdata(dev)); struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - spi_unregister_master(master); clk_disable_unprepare(mps->clk_mclk); free_irq(mps->irq, mps); if (mps->psc) iounmap(mps->psc); - spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 6e925dc3439..00ba910ab30 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -383,8 +383,8 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, mps->irq = irq; if (pdata == NULL) { - dev_warn(dev, "probe called without platform data, no " - "cs_control function will be called\n"); + dev_warn(dev, + "probe called without platform data, no cs_control function will be called\n"); mps->cs_control = NULL; mps->sysclk = 0; master->bus_num = bus_num; diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index de7b1141b90..de333059a9a 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -57,34 +57,53 @@ #define SG_MAXLEN 0xff00 +/* + * Flags for txrx functions. More efficient that using an argument register for + * each one. + */ +#define TXRX_WRITE (1<<0) /* This is a write */ +#define TXRX_DEASSERT_CS (1<<1) /* De-assert CS at end of txrx */ + struct mxs_spi { struct mxs_ssp ssp; struct completion c; + unsigned int sck; /* Rate requested (vs actual) */ }; static int mxs_spi_setup_transfer(struct spi_device *dev, - struct spi_transfer *t) + const struct spi_transfer *t) { struct mxs_spi *spi = spi_master_get_devdata(dev->master); struct mxs_ssp *ssp = &spi->ssp; - uint32_t hz = 0; + const unsigned int hz = min(dev->max_speed_hz, t->speed_hz); - hz = dev->max_speed_hz; - if (t && t->speed_hz) - hz = min(hz, t->speed_hz); if (hz == 0) { - dev_err(&dev->dev, "Cannot continue with zero clock\n"); + dev_err(&dev->dev, "SPI clock rate of zero not allowed\n"); return -EINVAL; } - mxs_ssp_set_clk_rate(ssp, hz); + if (hz != spi->sck) { + mxs_ssp_set_clk_rate(ssp, hz); + /* + * Save requested rate, hz, rather than the actual rate, + * ssp->clk_rate. Otherwise we would set the rate every trasfer + * when the actual rate is not quite the same as requested rate. + */ + spi->sck = hz; + /* + * Perhaps we should return an error if the actual clock is + * nowhere close to what was requested? + */ + } + + writel(BM_SSP_CTRL0_LOCK_CS, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) | - BF_SSP_CTRL1_WORD_LENGTH - (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | - ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | - ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), - ssp->base + HW_SSP_CTRL1(ssp)); + BF_SSP_CTRL1_WORD_LENGTH(BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) | + ((dev->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) | + ((dev->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0), + ssp->base + HW_SSP_CTRL1(ssp)); writel(0x0, ssp->base + HW_SSP_CMD0); writel(0x0, ssp->base + HW_SSP_CMD1); @@ -94,26 +113,15 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, static int mxs_spi_setup(struct spi_device *dev) { - int err = 0; - if (!dev->bits_per_word) dev->bits_per_word = 8; - if (dev->mode & ~(SPI_CPOL | SPI_CPHA)) - return -EINVAL; - - err = mxs_spi_setup_transfer(dev, NULL); - if (err) { - dev_err(&dev->dev, - "Failed to setup transfer, error = %d\n", err); - } - - return err; + return 0; } -static uint32_t mxs_spi_cs_to_reg(unsigned cs) +static u32 mxs_spi_cs_to_reg(unsigned cs) { - uint32_t select = 0; + u32 select = 0; /* * i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0 @@ -131,43 +139,11 @@ static uint32_t mxs_spi_cs_to_reg(unsigned cs) return select; } -static void mxs_spi_set_cs(struct mxs_spi *spi, unsigned cs) -{ - const uint32_t mask = - BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ; - uint32_t select; - struct mxs_ssp *ssp = &spi->ssp; - - writel(mask, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); - select = mxs_spi_cs_to_reg(cs); - writel(select, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); -} - -static inline void mxs_spi_enable(struct mxs_spi *spi) -{ - struct mxs_ssp *ssp = &spi->ssp; - - writel(BM_SSP_CTRL0_LOCK_CS, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - writel(BM_SSP_CTRL0_IGNORE_CRC, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); -} - -static inline void mxs_spi_disable(struct mxs_spi *spi) -{ - struct mxs_ssp *ssp = &spi->ssp; - - writel(BM_SSP_CTRL0_LOCK_CS, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); - writel(BM_SSP_CTRL0_IGNORE_CRC, - ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); -} - static int mxs_ssp_wait(struct mxs_spi *spi, int offset, int mask, bool set) { const unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT); struct mxs_ssp *ssp = &spi->ssp; - uint32_t reg; + u32 reg; do { reg = readl_relaxed(ssp->base + offset); @@ -200,9 +176,9 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, +static int mxs_spi_txrx_dma(struct mxs_spi *spi, unsigned char *buf, int len, - int *first, int *last, int write) + unsigned int flags) { struct mxs_ssp *ssp = &spi->ssp; struct dma_async_tx_descriptor *desc = NULL; @@ -211,11 +187,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, const int sgs = DIV_ROUND_UP(len, desc_len); int sg_count; int min, ret; - uint32_t ctrl0; + u32 ctrl0; struct page *vm_page; void *sg_buf; struct { - uint32_t pio[4]; + u32 pio[4]; struct scatterlist sg; } *dma_xfer; @@ -228,21 +204,25 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, INIT_COMPLETION(spi->c); + /* Chip select was already programmed into CTRL0 */ ctrl0 = readl(ssp->base + HW_SSP_CTRL0); - ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT; - ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs); + ctrl0 &= ~(BM_SSP_CTRL0_XFER_COUNT | BM_SSP_CTRL0_IGNORE_CRC | + BM_SSP_CTRL0_READ); + ctrl0 |= BM_SSP_CTRL0_DATA_XFER; - if (*first) - ctrl0 |= BM_SSP_CTRL0_LOCK_CS; - if (!write) + if (!(flags & TXRX_WRITE)) ctrl0 |= BM_SSP_CTRL0_READ; /* Queue the DMA data transfer. */ for (sg_count = 0; sg_count < sgs; sg_count++) { + /* Prepare the transfer descriptor. */ min = min(len, desc_len); - /* Prepare the transfer descriptor. */ - if ((sg_count + 1 == sgs) && *last) + /* + * De-assert CS on last segment if flag is set (i.e., no more + * transfers will follow) + */ + if ((sg_count + 1 == sgs) && (flags & TXRX_DEASSERT_CS)) ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC; if (ssp->devid == IMX23_SSP) { @@ -267,7 +247,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min); ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); len -= min; buf += min; @@ -287,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs, desc = dmaengine_prep_slave_sg(ssp->dmach, &dma_xfer[sg_count].sg, 1, - write ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, + (flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -324,7 +304,7 @@ err_vmalloc: while (--sg_count >= 0) { err_mapped: dma_unmap_sg(ssp->dev, &dma_xfer[sg_count].sg, 1, - write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + (flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } kfree(dma_xfer); @@ -332,20 +312,19 @@ err_mapped: return ret; } -static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, +static int mxs_spi_txrx_pio(struct mxs_spi *spi, unsigned char *buf, int len, - int *first, int *last, int write) + unsigned int flags) { struct mxs_ssp *ssp = &spi->ssp; - if (*first) - mxs_spi_enable(spi); - - mxs_spi_set_cs(spi, cs); + writel(BM_SSP_CTRL0_IGNORE_CRC, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); while (len--) { - if (*last && len == 0) - mxs_spi_disable(spi); + if (len == 0 && (flags & TXRX_DEASSERT_CS)) + writel(BM_SSP_CTRL0_IGNORE_CRC, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); if (ssp->devid == IMX23_SSP) { writel(BM_SSP_CTRL0_XFER_COUNT, @@ -356,7 +335,7 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, writel(1, ssp->base + HW_SSP_XFER_SIZE); } - if (write) + if (flags & TXRX_WRITE) writel(BM_SSP_CTRL0_READ, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); else @@ -369,13 +348,13 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs, if (mxs_ssp_wait(spi, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN, 1)) return -ETIMEDOUT; - if (write) + if (flags & TXRX_WRITE) writel(*buf, ssp->base + HW_SSP_DATA(ssp)); writel(BM_SSP_CTRL0_DATA_XFER, ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - if (!write) { + if (!(flags & TXRX_WRITE)) { if (mxs_ssp_wait(spi, HW_SSP_STATUS(ssp), BM_SSP_STATUS_FIFO_EMPTY, 0)) return -ETIMEDOUT; @@ -400,14 +379,15 @@ static int mxs_spi_transfer_one(struct spi_master *master, { struct mxs_spi *spi = spi_master_get_devdata(master); struct mxs_ssp *ssp = &spi->ssp; - int first, last; struct spi_transfer *t, *tmp_t; + unsigned int flag; int status = 0; - int cs; - - first = last = 0; - cs = m->spi->chip_select; + /* Program CS register bits here, it will be used for all transfers. */ + writel(BM_SSP_CTRL0_WAIT_FOR_CMD | BM_SSP_CTRL0_WAIT_FOR_IRQ, + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); + writel(mxs_spi_cs_to_reg(m->spi->chip_select), + ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { @@ -415,16 +395,9 @@ static int mxs_spi_transfer_one(struct spi_master *master, if (status) break; - if (&t->transfer_list == m->transfers.next) - first = 1; - if (&t->transfer_list == m->transfers.prev) - last = 1; - if ((t->rx_buf && t->tx_buf) || (t->rx_dma && t->tx_dma)) { - dev_err(ssp->dev, - "Cannot send and receive simultaneously\n"); - status = -EINVAL; - break; - } + /* De-assert on last transfer, inverted by cs_change flag */ + flag = (&t->transfer_list == m->transfers.prev) ^ t->cs_change ? + TXRX_DEASSERT_CS : 0; /* * Small blocks can be transfered via PIO. @@ -441,26 +414,26 @@ static int mxs_spi_transfer_one(struct spi_master *master, STMP_OFFSET_REG_CLR); if (t->tx_buf) - status = mxs_spi_txrx_pio(spi, cs, + status = mxs_spi_txrx_pio(spi, (void *)t->tx_buf, - t->len, &first, &last, 1); + t->len, flag | TXRX_WRITE); if (t->rx_buf) - status = mxs_spi_txrx_pio(spi, cs, + status = mxs_spi_txrx_pio(spi, t->rx_buf, t->len, - &first, &last, 0); + flag); } else { writel(BM_SSP_CTRL1_DMA_ENABLE, ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_SET); if (t->tx_buf) - status = mxs_spi_txrx_dma(spi, cs, + status = mxs_spi_txrx_dma(spi, (void *)t->tx_buf, t->len, - &first, &last, 1); + flag | TXRX_WRITE); if (t->rx_buf) - status = mxs_spi_txrx_dma(spi, cs, + status = mxs_spi_txrx_dma(spi, t->rx_buf, t->len, - &first, &last, 0); + flag); } if (status) { @@ -469,7 +442,6 @@ static int mxs_spi_transfer_one(struct spi_master *master, } m->actual_length += t->len; - first = last = 0; } m->status = status; @@ -563,7 +535,6 @@ static int mxs_spi_probe(struct platform_device *pdev) goto out_dma_release; clk_set_rate(ssp->clk, clk_freq); - ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; ret = stmp_reset_block(ssp->base); if (ret) @@ -571,7 +542,7 @@ static int mxs_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret) { dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret); goto out_disable_clk; @@ -598,10 +569,8 @@ static int mxs_spi_remove(struct platform_device *pdev) spi = spi_master_get_devdata(master); ssp = &spi->ssp; - spi_unregister_master(master); clk_disable_unprepare(ssp->clk); dma_release_channel(ssp->dmach); - spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 47a68b43bcd..e0c32bc69ee 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -349,7 +349,7 @@ static int nuc900_spi_probe(struct platform_device *pdev) } hw = spi_master_get_devdata(master); - hw->master = spi_master_get(master); + hw->master = master; hw->pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; @@ -435,7 +435,6 @@ err_iomap: kfree(hw->ioarea); err_pdata: spi_master_put(hw->master); - err_nomem: return err; } diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 333cb1badcd..91c66859620 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -306,7 +306,7 @@ static int tiny_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hw); /* setup the state for the bitbang driver */ - hw->bitbang.master = spi_master_get(master); + hw->bitbang.master = master; if (!hw->bitbang.master) return err; hw->bitbang.setup_transfer = tiny_spi_setup_transfer; diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 5f28ddbe4f7..67249a48b39 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -272,7 +272,7 @@ static int octeon_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = pdev->dev.of_node; - err = spi_register_master(master); + err = devm_spi_register_master(&pdev->dev, master); if (err) { dev_err(&pdev->dev, "register master failed: %d\n", err); goto fail; @@ -292,8 +292,6 @@ static int octeon_spi_remove(struct platform_device *pdev) struct octeon_spi *p = spi_master_get_devdata(master); u64 register_base = p->register_base; - spi_unregister_master(master); - /* Clear the CSENA* and put everything in a known state. */ cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 69ecf05757d..b6ed82beb01 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -457,7 +457,7 @@ static int omap1_spi100k_probe(struct platform_device *pdev) goto err; } - status = spi_register_master(master); + status = devm_spi_register_master(&pdev->dev, master); if (status < 0) goto err; @@ -485,8 +485,6 @@ static int omap1_spi100k_remove(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - spi_unregister_master(master); - return 0; } diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index a6a8f096175..9313fd3b413 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -557,7 +557,8 @@ static struct platform_driver uwire_driver = { .name = "omap_uwire", .owner = THIS_MODULE, }, - .remove = uwire_remove, + .probe = uwire_probe, + .remove = uwire_remove, // suspend ... unuse ck // resume ... use ck }; @@ -579,7 +580,7 @@ static int __init omap_uwire_init(void) omap_writel(val | 0x00AAA000, OMAP7XX_IO_CONF_9); } - return platform_driver_probe(&uwire_driver, uwire_probe); + return platform_driver_register(&uwire_driver); } static void __exit omap_uwire_exit(void) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index ed4af4708d9..443df39840b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -276,7 +276,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; unsigned int wcnt; - int fifo_depth, bytes_per_word; + int max_fifo_depth, fifo_depth, bytes_per_word; u32 chconf, xferlevel; mcspi = spi_master_get_devdata(master); @@ -287,7 +287,12 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, if (t->len % bytes_per_word != 0) goto disable_fifo; - fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH); + if (t->rx_buf != NULL && t->tx_buf != NULL) + max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2; + else + max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; + + fifo_depth = gcd(t->len, max_fifo_depth); if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) goto disable_fifo; @@ -299,7 +304,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; xferlevel |= (fifo_depth - 1) << 8; - } else { + } + if (t->tx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFET; xferlevel |= fifo_depth - 1; } @@ -498,7 +504,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ((u32 *)xfer->rx_buf)[elements++] = w; } else { int bytes_per_word = mcspi_bytes_per_word(word_len); - dev_err(&spi->dev, "DMA RX penultimate word empty"); + dev_err(&spi->dev, "DMA RX penultimate word empty\n"); count -= (bytes_per_word << 1); omap2_mcspi_set_enable(spi, 1); return count; @@ -516,7 +522,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, else /* word_len <= 32 */ ((u32 *)xfer->rx_buf)[elements] = w; } else { - dev_err(&spi->dev, "DMA RX last word empty"); + dev_err(&spi->dev, "DMA RX last word empty\n"); count -= mcspi_bytes_per_word(word_len); } omap2_mcspi_set_enable(spi, 1); @@ -1407,7 +1413,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) if (status < 0) goto disable_pm; - status = spi_register_master(master); + status = devm_spi_register_master(&pdev->dev, master); if (status < 0) goto disable_pm; @@ -1435,7 +1441,6 @@ static int omap2_mcspi_remove(struct platform_device *pdev) pm_runtime_put_sync(mcspi->dev); pm_runtime_disable(&pdev->dev); - spi_unregister_master(master); kfree(dma_channels); return 0; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 1d1d321d90c..744841e095e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -84,8 +84,8 @@ static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size) orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, ORION_SPI_IF_8_16_BIT_MODE); } else { - pr_debug("Bad bits per word value %d (only 8 or 16 are " - "allowed).\n", size); + pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n", + size); return -EINVAL; } @@ -407,7 +407,7 @@ static int orion_spi_probe(struct platform_device *pdev) const u32 *iprop; int size; - master = spi_alloc_master(&pdev->dev, sizeof *spi); + master = spi_alloc_master(&pdev->dev, sizeof(*spi)); if (master == NULL) { dev_dbg(&pdev->dev, "master allocation failed\n"); return -ENOMEM; @@ -457,7 +457,7 @@ static int orion_spi_probe(struct platform_device *pdev) goto out_rel_clk; master->dev.of_node = pdev->dev.of_node; - status = spi_register_master(master); + status = devm_spi_register_master(&pdev->dev, master); if (status < 0) goto out_rel_clk; @@ -483,8 +483,6 @@ static int orion_spi_remove(struct platform_device *pdev) clk_disable_unprepare(spi->clk); clk_put(spi->clk); - spi_unregister_master(master); - return 0; } diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 9c511a954d2..2789b452e71 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1619,7 +1619,6 @@ static int verify_controller_parameters(struct pl022 *pl022, dev_err(&pl022->adev->dev, "RX FIFO Trigger Level is configured incorrectly\n"); return -EINVAL; - break; } switch (chip_info->tx_lev_trig) { case SSP_TX_1_OR_MORE_EMPTY_LOC: @@ -1645,7 +1644,6 @@ static int verify_controller_parameters(struct pl022 *pl022, dev_err(&pl022->adev->dev, "TX FIFO Trigger Level is configured incorrectly\n"); return -EINVAL; - break; } if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) { if ((chip_info->ctrl_len < SSP_BITS_4) @@ -2175,8 +2173,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) status = -ENOMEM; goto err_no_ioremap; } - printk(KERN_INFO "pl022: mapped registers from %pa to %p\n", - &adev->res.start, pl022->virtbase); + dev_info(&adev->dev, "mapped registers from %pa to %p\n", + &adev->res.start, pl022->virtbase); pl022->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(pl022->clk)) { @@ -2227,7 +2225,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) /* Register with the SPI framework */ amba_set_drvdata(adev, pl022); - status = spi_register_master(master); + status = devm_spi_register_master(&adev->dev, master); if (status != 0) { dev_err(&adev->dev, "probe - problem registering spi master\n"); @@ -2287,8 +2285,6 @@ pl022_remove(struct amba_device *adev) clk_unprepare(pl022->clk); amba_release_regions(adev); tasklet_disable(&pl022->pump_transfers); - spi_unregister_master(pl022->master); - amba_set_drvdata(adev, NULL); return 0; } diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 0ee53c25ba5..5ee56726f8d 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -29,6 +29,8 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/wait.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> @@ -396,7 +398,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) master->dev.of_node = np; platform_set_drvdata(op, master); hw = spi_master_get_devdata(master); - hw->master = spi_master_get(master); + hw->master = master; hw->dev = dev; init_completion(&hw->done); @@ -558,6 +560,7 @@ static int spi_ppc4xx_of_remove(struct platform_device *op) free_irq(hw->irqnum, hw); iounmap(hw->regs); free_gpios(hw); + spi_master_put(master); return 0; } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index c1a50674c1e..cb0e1f1137a 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -573,8 +573,8 @@ static irqreturn_t ssp_int(int irq, void *dev_id) write_SSTO(0, reg); write_SSSR_CS(drv_data, drv_data->clear_sr); - dev_err(&drv_data->pdev->dev, "bad message state " - "in interrupt handler\n"); + dev_err(&drv_data->pdev->dev, + "bad message state in interrupt handler\n"); /* Never fail */ return IRQ_HANDLED; @@ -651,8 +651,8 @@ static void pump_transfers(unsigned long data) if (message->is_dma_mapped || transfer->rx_dma || transfer->tx_dma) { dev_err(&drv_data->pdev->dev, - "pump_transfers: mapped transfer length " - "of %u is greater than %d\n", + "pump_transfers: mapped transfer length of " + "%u is greater than %d\n", transfer->len, MAX_DMA_LEN); message->status = -EINVAL; giveback(drv_data); @@ -660,11 +660,10 @@ static void pump_transfers(unsigned long data) } /* warn ... we force this to PIO mode */ - if (printk_ratelimit()) - dev_warn(&message->spi->dev, "pump_transfers: " - "DMA disabled for transfer length %ld " - "greater than %d\n", - (long)drv_data->len, MAX_DMA_LEN); + dev_warn_ratelimited(&message->spi->dev, + "pump_transfers: DMA disabled for transfer length %ld " + "greater than %d\n", + (long)drv_data->len, MAX_DMA_LEN); } /* Setup the transfer state based on the type of transfer */ @@ -726,11 +725,8 @@ static void pump_transfers(unsigned long data) message->spi, bits, &dma_burst, &dma_thresh)) - if (printk_ratelimit()) - dev_warn(&message->spi->dev, - "pump_transfers: " - "DMA burst size reduced to " - "match bits_per_word\n"); + dev_warn_ratelimited(&message->spi->dev, + "pump_transfers: DMA burst size reduced to match bits_per_word\n"); } cr0 = clk_div @@ -854,8 +850,8 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip, if (gpio_is_valid(chip_info->gpio_cs)) { err = gpio_request(chip_info->gpio_cs, "SPI_CS"); if (err) { - dev_err(&spi->dev, "failed to request chip select " - "GPIO%d\n", chip_info->gpio_cs); + dev_err(&spi->dev, "failed to request chip select GPIO%d\n", + chip_info->gpio_cs); return err; } @@ -899,8 +895,8 @@ static int setup(struct spi_device *spi) if (drv_data->ssp_type == CE4100_SSP) { if (spi->chip_select > 4) { - dev_err(&spi->dev, "failed setup: " - "cs number must not be > 4.\n"); + dev_err(&spi->dev, + "failed setup: cs number must not be > 4.\n"); kfree(chip); return -EINVAL; } @@ -956,8 +952,8 @@ static int setup(struct spi_device *spi) spi->bits_per_word, &chip->dma_burst_size, &chip->dma_threshold)) { - dev_warn(&spi->dev, "in setup: DMA burst size reduced " - "to match bits_per_word\n"); + dev_warn(&spi->dev, + "in setup: DMA burst size reduced to match bits_per_word\n"); } } @@ -1205,7 +1201,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); - status = spi_register_master(master); + status = devm_spi_register_master(&pdev->dev, master); if (status != 0) { dev_err(&pdev->dev, "problem registering spi master\n"); goto out_error_clock_enabled; @@ -1257,9 +1253,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) /* Release SSP */ pxa_ssp_free(ssp); - /* Disconnect from the SPI framework */ - spi_unregister_master(drv_data->master); - return 0; } diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 8719206a03a..58449ad4ad0 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -59,6 +59,14 @@ #define RSPI_SPCMD6 0x1c #define RSPI_SPCMD7 0x1e +/*qspi only */ +#define QSPI_SPBFCR 0x18 +#define QSPI_SPBDCR 0x1a +#define QSPI_SPBMUL0 0x1c +#define QSPI_SPBMUL1 0x20 +#define QSPI_SPBMUL2 0x24 +#define QSPI_SPBMUL3 0x28 + /* SPCR */ #define SPCR_SPRIE 0x80 #define SPCR_SPE 0x40 @@ -126,6 +134,8 @@ #define SPCMD_LSBF 0x1000 #define SPCMD_SPB_MASK 0x0f00 #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) +#define SPCMD_SPB_8BIT 0x0000 /* qspi only */ +#define SPCMD_SPB_16BIT 0x0100 #define SPCMD_SPB_20BIT 0x0000 #define SPCMD_SPB_24BIT 0x0100 #define SPCMD_SPB_32BIT 0x0200 @@ -135,6 +145,10 @@ #define SPCMD_CPOL 0x0002 #define SPCMD_CPHA 0x0001 +/* SPBFCR */ +#define SPBFCR_TXRST 0x80 /* qspi only */ +#define SPBFCR_RXRST 0x40 /* qspi only */ + struct rspi_data { void __iomem *addr; u32 max_speed_hz; @@ -145,6 +159,7 @@ struct rspi_data { spinlock_t lock; struct clk *clk; unsigned char spsr; + const struct spi_ops *ops; /* for dmaengine */ struct dma_chan *chan_tx; @@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset) iowrite16(data, rspi->addr + offset); } +static void rspi_write32(struct rspi_data *rspi, u32 data, u16 offset) +{ + iowrite32(data, rspi->addr + offset); +} + static u8 rspi_read8(struct rspi_data *rspi, u16 offset) { return ioread8(rspi->addr + offset); @@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset) return ioread16(rspi->addr + offset); } -static unsigned char rspi_calc_spbr(struct rspi_data *rspi) +/* optional functions */ +struct spi_ops { + int (*set_config_register)(struct rspi_data *rspi, int access_size); + int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t); + int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t); + +}; + +/* + * functions for RSPI + */ +static int rspi_set_config_register(struct rspi_data *rspi, int access_size) +{ + int spbr; + + /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ + rspi_write8(rspi, 0x00, RSPI_SPPCR); + + /* Sets transfer bit rate */ + spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; + rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + + /* Sets number of frames to be used: 1 frame */ + rspi_write8(rspi, 0x00, RSPI_SPDCR); + + /* Sets RSPCK, SSL, next-access delay value */ + rspi_write8(rspi, 0x00, RSPI_SPCKD); + rspi_write8(rspi, 0x00, RSPI_SSLND); + rspi_write8(rspi, 0x00, RSPI_SPND); + + /* Sets parity, interrupt mask */ + rspi_write8(rspi, 0x00, RSPI_SPCR2); + + /* Sets SPCMD */ + rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP, + RSPI_SPCMD0); + + /* Sets RSPI mode */ + rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); + + return 0; +} + +/* + * functions for QSPI + */ +static int qspi_set_config_register(struct rspi_data *rspi, int access_size) { - int tmp; - unsigned char spbr; + u16 spcmd; + int spbr; + + /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ + rspi_write8(rspi, 0x00, RSPI_SPPCR); + + /* Sets transfer bit rate */ + spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz); + rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); + + /* Sets number of frames to be used: 1 frame */ + rspi_write8(rspi, 0x00, RSPI_SPDCR); + + /* Sets RSPCK, SSL, next-access delay value */ + rspi_write8(rspi, 0x00, RSPI_SPCKD); + rspi_write8(rspi, 0x00, RSPI_SSLND); + rspi_write8(rspi, 0x00, RSPI_SPND); + + /* Data Length Setting */ + if (access_size == 8) + spcmd = SPCMD_SPB_8BIT; + else if (access_size == 16) + spcmd = SPCMD_SPB_16BIT; + else if (access_size == 32) + spcmd = SPCMD_SPB_32BIT; + + spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SSLKP | SPCMD_SPNDEN; + + /* Resets transfer data length */ + rspi_write32(rspi, 0, QSPI_SPBMUL0); + + /* Resets transmit and receive buffer */ + rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR); + /* Sets buffer to allow normal operation */ + rspi_write8(rspi, 0x00, QSPI_SPBFCR); + + /* Sets SPCMD */ + rspi_write16(rspi, spcmd, RSPI_SPCMD0); - tmp = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; - spbr = clamp(tmp, 0, 255); + /* Enables SPI function in a master mode */ + rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR); - return spbr; + return 0; } +#define set_config_register(spi, n) spi->ops->set_config_register(spi, n) + static void rspi_enable_irq(struct rspi_data *rspi, u8 enable) { rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR); @@ -220,54 +326,60 @@ static void rspi_negate_ssl(struct rspi_data *rspi) rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); } -static int rspi_set_config_register(struct rspi_data *rspi, int access_size) +static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t) { - /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ - rspi_write8(rspi, 0x00, RSPI_SPPCR); - - /* Sets transfer bit rate */ - rspi_write8(rspi, rspi_calc_spbr(rspi), RSPI_SPBR); - - /* Sets number of frames to be used: 1 frame */ - rspi_write8(rspi, 0x00, RSPI_SPDCR); + int remain = t->len; + u8 *data; - /* Sets RSPCK, SSL, next-access delay value */ - rspi_write8(rspi, 0x00, RSPI_SPCKD); - rspi_write8(rspi, 0x00, RSPI_SSLND); - rspi_write8(rspi, 0x00, RSPI_SPND); + data = (u8 *)t->tx_buf; + while (remain > 0) { + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, + RSPI_SPCR); - /* Sets parity, interrupt mask */ - rspi_write8(rspi, 0x00, RSPI_SPCR2); + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, + "%s: tx empty timeout\n", __func__); + return -ETIMEDOUT; + } - /* Sets SPCMD */ - rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP, - RSPI_SPCMD0); + rspi_write16(rspi, *data, RSPI_SPDR); + data++; + remain--; + } - /* Sets RSPI mode */ - rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); + /* Waiting for the last transmition */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); return 0; } -static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, +static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, struct spi_transfer *t) { int remain = t->len; u8 *data; + rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR); + rspi_write8(rspi, 0x00, QSPI_SPBFCR); + data = (u8 *)t->tx_buf; while (remain > 0) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, - RSPI_SPCR); if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { dev_err(&rspi->master->dev, "%s: tx empty timeout\n", __func__); return -ETIMEDOUT; } + rspi_write8(rspi, *data++, RSPI_SPDR); + + if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + dev_err(&rspi->master->dev, + "%s: receive timeout\n", __func__); + return -ETIMEDOUT; + } + rspi_read8(rspi, RSPI_SPDR); - rspi_write16(rspi, *data, RSPI_SPDR); - data++; remain--; } @@ -277,6 +389,8 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } +#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t) + static void rspi_dma_complete(void *arg) { struct rspi_data *rspi = arg; @@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } +static void qspi_receive_init(struct rspi_data *rspi) +{ + unsigned char spsr; + + spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPRF) + rspi_read8(rspi, RSPI_SPDR); /* dummy read */ + rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR); + rspi_write8(rspi, 0x00, QSPI_SPBFCR); +} + +static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, + struct spi_transfer *t) +{ + int remain = t->len; + u8 *data; + + qspi_receive_init(rspi); + + data = (u8 *)t->rx_buf; + while (remain > 0) { + + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, + "%s: tx empty timeout\n", __func__); + return -ETIMEDOUT; + } + /* dummy write for generate clock */ + rspi_write8(rspi, 0x00, RSPI_SPDR); + + if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + dev_err(&rspi->master->dev, + "%s: receive timeout\n", __func__); + return -ETIMEDOUT; + } + /* SPDR allows 8, 16 or 32-bit access */ + *data++ = rspi_read8(rspi, RSPI_SPDR); + remain--; + } + + return 0; +} + +#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t) + static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { struct scatterlist sg, sg_dummy; @@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work) if (rspi_is_dma(rspi, t)) ret = rspi_send_dma(rspi, t); else - ret = rspi_send_pio(rspi, mesg, t); + ret = send_pio(rspi, mesg, t); if (ret < 0) goto error; } @@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work) if (rspi_is_dma(rspi, t)) ret = rspi_receive_dma(rspi, t); else - ret = rspi_receive_pio(rspi, mesg, t); + ret = receive_pio(rspi, mesg, t); if (ret < 0) goto error; } @@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi) spi->bits_per_word = 8; rspi->max_speed_hz = spi->max_speed_hz; - rspi_set_config_register(rspi, 8); + set_config_register(rspi, 8); return 0; } @@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev) struct rspi_data *rspi; int ret, irq; char clk_name[16]; - + struct rspi_plat_data *rspi_pd = pdev->dev.platform_data; + const struct spi_ops *ops; + const struct platform_device_id *id_entry = pdev->id_entry; + + ops = (struct spi_ops *)id_entry->driver_data; + /* ops parameter check */ + if (!ops->set_config_register) { + dev_err(&pdev->dev, "there is no set_config_register\n"); + return -ENODEV; + } /* get base addr */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (unlikely(res == NULL)) { @@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev) rspi = spi_master_get_devdata(master); platform_set_drvdata(pdev, rspi); - + rspi->ops = ops; rspi->master = master; rspi->addr = ioremap(res->start, resource_size(res)); if (rspi->addr == NULL) { @@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } - snprintf(clk_name, sizeof(clk_name), "rspi%d", pdev->id); + snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id); rspi->clk = clk_get(&pdev->dev, clk_name); if (IS_ERR(rspi->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); @@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev) INIT_WORK(&rspi->ws, rspi_work); init_waitqueue_head(&rspi->wait); - master->num_chipselect = 2; + master->num_chipselect = rspi_pd->num_chipselect; + if (!master->num_chipselect) + master->num_chipselect = 2; /* default */ + master->bus_num = pdev->id; master->setup = rspi_setup; master->transfer = rspi_transfer; @@ -832,11 +1003,32 @@ error1: return ret; } +static struct spi_ops rspi_ops = { + .set_config_register = rspi_set_config_register, + .send_pio = rspi_send_pio, + .receive_pio = rspi_receive_pio, +}; + +static struct spi_ops qspi_ops = { + .set_config_register = qspi_set_config_register, + .send_pio = qspi_send_pio, + .receive_pio = qspi_receive_pio, +}; + +static struct platform_device_id spi_driver_ids[] = { + { "rspi", (kernel_ulong_t)&rspi_ops }, + { "qspi", (kernel_ulong_t)&qspi_ops }, + {}, +}; + +MODULE_DEVICE_TABLE(platform, spi_driver_ids); + static struct platform_driver rspi_driver = { .probe = rspi_probe, .remove = rspi_remove, + .id_table = spi_driver_ids, .driver = { - .name = "rspi", + .name = "renesas_spi", .owner = THIS_MODULE, }, }; diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index ce318d95a6e..0dc32a11bd3 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -280,7 +280,7 @@ static inline u32 ack_bit(unsigned int irq) * so the caller does not need to do anything more than start the transfer * as normal, since the IRQ will have been re-routed to the FIQ handler. */ -void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) +static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) { struct pt_regs regs; enum spi_fiq_mode mode; @@ -524,7 +524,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); memset(hw, 0, sizeof(struct s3c24xx_spi)); - hw->master = spi_master_get(master); + hw->master = master; hw->pdata = pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index a80376dc3a1..9e2020df9e0 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data { #endif struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; - unsigned long gpios[4]; bool cs_gpio; }; @@ -559,25 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs; - if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ /* Deselect the last toggled device */ - cs = sdd->tgl_spi->controller_data; - if (sdd->cs_gpio) - gpio_set_value(cs->line, + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); } sdd->tgl_spi = NULL; } - cs = spi->controller_data; - if (sdd->cs_gpio) - gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0); - - /* Start the signals */ - writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); } static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, @@ -702,16 +694,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs = spi->controller_data; - if (sdd->tgl_spi == spi) sdd->tgl_spi = NULL; - if (sdd->cs_gpio) - gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1); - - /* Quiese the signals */ - writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); } static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) @@ -862,16 +849,12 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, } } -static int s3c64xx_spi_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static int s3c64xx_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; struct s3c64xx_spi_csinfo *cs = spi->controller_data; - struct spi_transfer *xfer; - int status = 0, cs_toggle = 0; - u32 speed; - u8 bpw; /* If Master's(controller) state differs from that needed by Slave */ if (sdd->cur_speed != spi->max_speed_hz @@ -887,106 +870,98 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master, if (s3c64xx_spi_map_mssg(sdd, msg)) { dev_err(&spi->dev, "Xfer: Unable to map message buffers!\n"); - status = -ENOMEM; - goto out; + return -ENOMEM; } /* Configure feedback delay */ writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - unsigned long flags; - int use_dma; - - INIT_COMPLETION(sdd->xfer_completion); - - /* Only BPW and Speed may change across transfers */ - bpw = xfer->bits_per_word; - speed = xfer->speed_hz ? : spi->max_speed_hz; - - if (xfer->len % (bpw / 8)) { - dev_err(&spi->dev, - "Xfer length(%u) not a multiple of word size(%u)\n", - xfer->len, bpw / 8); - status = -EIO; - goto out; - } + return 0; +} - if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { - sdd->cur_bpw = bpw; - sdd->cur_speed = speed; - s3c64xx_spi_config(sdd); - } +static int s3c64xx_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + int status; + u32 speed; + u8 bpw; + unsigned long flags; + int use_dma; - /* Polling method for xfers not bigger than FIFO capacity */ - use_dma = 0; - if (!is_polling(sdd) && - (sdd->rx_dma.ch && sdd->tx_dma.ch && - (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) - use_dma = 1; + INIT_COMPLETION(sdd->xfer_completion); - spin_lock_irqsave(&sdd->lock, flags); + /* Only BPW and Speed may change across transfers */ + bpw = xfer->bits_per_word; + speed = xfer->speed_hz ? : spi->max_speed_hz; - /* Pending only which is to be done */ - sdd->state &= ~RXBUSY; - sdd->state &= ~TXBUSY; + if (xfer->len % (bpw / 8)) { + dev_err(&spi->dev, + "Xfer length(%u) not a multiple of word size(%u)\n", + xfer->len, bpw / 8); + return -EIO; + } - enable_datapath(sdd, spi, xfer, use_dma); + if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { + sdd->cur_bpw = bpw; + sdd->cur_speed = speed; + s3c64xx_spi_config(sdd); + } - /* Slave Select */ - enable_cs(sdd, spi); + /* Polling method for xfers not bigger than FIFO capacity */ + use_dma = 0; + if (!is_polling(sdd) && + (sdd->rx_dma.ch && sdd->tx_dma.ch && + (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))) + use_dma = 1; - spin_unlock_irqrestore(&sdd->lock, flags); + spin_lock_irqsave(&sdd->lock, flags); - status = wait_for_xfer(sdd, xfer, use_dma); + /* Pending only which is to be done */ + sdd->state &= ~RXBUSY; + sdd->state &= ~TXBUSY; - if (status) { - dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", - xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, - (sdd->state & RXBUSY) ? 'f' : 'p', - (sdd->state & TXBUSY) ? 'f' : 'p', - xfer->len); + enable_datapath(sdd, spi, xfer, use_dma); - if (use_dma) { - if (xfer->tx_buf != NULL - && (sdd->state & TXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); - if (xfer->rx_buf != NULL - && (sdd->state & RXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); - } + /* Start the signals */ + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - goto out; - } + /* Start the signals */ + writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); + spin_unlock_irqrestore(&sdd->lock, flags); - if (xfer->cs_change) { - /* Hint that the next mssg is gonna be - for the same device */ - if (list_is_last(&xfer->transfer_list, - &msg->transfers)) - cs_toggle = 1; + status = wait_for_xfer(sdd, xfer, use_dma); + + if (status) { + dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", + xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, + (sdd->state & RXBUSY) ? 'f' : 'p', + (sdd->state & TXBUSY) ? 'f' : 'p', + xfer->len); + + if (use_dma) { + if (xfer->tx_buf != NULL + && (sdd->state & TXBUSY)) + s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); + if (xfer->rx_buf != NULL + && (sdd->state & RXBUSY)) + s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); } - - msg->actual_length += xfer->len; - + } else { flush_fifo(sdd); } -out: - if (!cs_toggle || status) - disable_cs(sdd, spi); - else - sdd->tgl_spi = spi; - - s3c64xx_spi_unmap_mssg(sdd, msg); + return status; +} - msg->status = status; +static int s3c64xx_spi_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - spi_finalize_current_message(master); + s3c64xx_spi_unmap_mssg(sdd, msg); return 0; } @@ -1071,6 +1046,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) cs->line, err); goto err_gpio_req; } + + spi->cs_gpio = cs->line; } spi_set_ctldata(spi, cs); @@ -1117,11 +1094,14 @@ static int s3c64xx_spi_setup(struct spi_device *spi) } pm_runtime_put(&sdd->pdev->dev); + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); disable_cs(sdd, spi); return 0; setup_exit: + pm_runtime_put(&sdd->pdev->dev); /* setup() returns with device de-selected */ + writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); disable_cs(sdd, spi); gpio_free(cs->line); @@ -1140,8 +1120,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) struct s3c64xx_spi_driver_data *sdd; sdd = spi_master_get_devdata(spi->master); - if (cs && sdd->cs_gpio) { - gpio_free(cs->line); + if (spi->cs_gpio) { + gpio_free(spi->cs_gpio); if (spi->dev.of_node) kfree(cs); } @@ -1359,7 +1339,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->setup = s3c64xx_spi_setup; master->cleanup = s3c64xx_spi_cleanup; master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; - master->transfer_one_message = s3c64xx_spi_transfer_one_message; + master->prepare_message = s3c64xx_spi_prepare_message; + master->transfer_one = s3c64xx_spi_transfer_one; + master->unprepare_message = s3c64xx_spi_unprepare_message; master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; @@ -1428,11 +1410,12 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, sdd->regs + S3C64XX_SPI_INT_EN); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - if (spi_register_master(master)) { - dev_err(&pdev->dev, "cannot register SPI master\n"); - ret = -EBUSY; + ret = devm_spi_register_master(&pdev->dev, master); + if (ret != 0) { + dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret); goto err3; } @@ -1461,16 +1444,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - spi_unregister_master(master); - writel(0, sdd->regs + S3C64XX_SPI_INT_EN); clk_disable_unprepare(sdd->src_clk); clk_disable_unprepare(sdd->clk); - spi_master_put(master); - return 0; } @@ -1480,11 +1459,14 @@ static int s3c64xx_spi_suspend(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - spi_master_suspend(master); + int ret = spi_master_suspend(master); + if (ret) + return ret; - /* Disable the clock */ - clk_disable_unprepare(sdd->src_clk); - clk_disable_unprepare(sdd->clk); + if (!pm_runtime_suspended(dev)) { + clk_disable_unprepare(sdd->clk); + clk_disable_unprepare(sdd->src_clk); + } sdd->cur_speed = 0; /* Output Clock is stopped */ @@ -1500,15 +1482,14 @@ static int s3c64xx_spi_resume(struct device *dev) if (sci->cfg_gpio) sci->cfg_gpio(); - /* Enable the clock */ - clk_prepare_enable(sdd->src_clk); - clk_prepare_enable(sdd->clk); + if (!pm_runtime_suspended(dev)) { + clk_prepare_enable(sdd->src_clk); + clk_prepare_enable(sdd->clk); + } s3c64xx_spi_hwinit(sdd, sdd->port_id); - spi_master_resume(master); - - return 0; + return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ @@ -1528,9 +1509,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + int ret; - clk_prepare_enable(sdd->src_clk); - clk_prepare_enable(sdd->clk); + ret = clk_prepare_enable(sdd->src_clk); + if (ret != 0) + return ret; + + ret = clk_prepare_enable(sdd->clk); + if (ret != 0) { + clk_disable_unprepare(sdd->src_clk); + return ret; + } return 0; } @@ -1616,6 +1605,18 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = { }; static const struct of_device_id s3c64xx_spi_dt_match[] = { + { .compatible = "samsung,s3c2443-spi", + .data = (void *)&s3c2443_spi_port_config, + }, + { .compatible = "samsung,s3c6410-spi", + .data = (void *)&s3c6410_spi_port_config, + }, + { .compatible = "samsung,s5pc100-spi", + .data = (void *)&s5pc100_spi_port_config, + }, + { .compatible = "samsung,s5pv210-spi", + .data = (void *)&s5pv210_spi_port_config, + }, { .compatible = "samsung,exynos4210-spi", .data = (void *)&exynos4_spi_port_config, }, @@ -1633,22 +1634,13 @@ static struct platform_driver s3c64xx_spi_driver = { .pm = &s3c64xx_spi_pm, .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), }, + .probe = s3c64xx_spi_probe, .remove = s3c64xx_spi_remove, .id_table = s3c64xx_spi_driver_ids, }; MODULE_ALIAS("platform:s3c64xx-spi"); -static int __init s3c64xx_spi_init(void) -{ - return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe); -} -subsys_initcall(s3c64xx_spi_init); - -static void __exit s3c64xx_spi_exit(void) -{ - platform_driver_unregister(&s3c64xx_spi_driver); -} -module_exit(s3c64xx_spi_exit); +module_platform_driver(s3c64xx_spi_driver); MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>"); MODULE_DESCRIPTION("S3C64XX SPI Controller Driver"); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index e488a90a98b..292567ab4c6 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -137,7 +137,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, rate /= 16; /* CLKCx calculation */ - rate /= (((idiv_clk & 0x1F) + 1) * 2) ; + rate /= (((idiv_clk & 0x1F) + 1) * 2); /* save best settings */ tmp = abs(target_rate - rate); @@ -303,9 +303,10 @@ static int hspi_probe(struct platform_device *pdev) master->setup = hspi_setup; master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; + master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); goto error1; @@ -328,17 +329,23 @@ static int hspi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); clk_put(hspi->clk); - spi_unregister_master(hspi->master); return 0; } +static struct of_device_id hspi_of_match[] = { + { .compatible = "renesas,hspi", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hspi_of_match); + static struct platform_driver hspi_driver = { .probe = hspi_probe, .remove = hspi_remove, .driver = { .name = "sh-hspi", .owner = THIS_MODULE, + .of_match_table = hspi_of_match, }, }; module_platform_driver(hspi_driver); diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 8eefeb6007d..38eb24df796 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -133,7 +133,7 @@ static int sh_sci_spi_probe(struct platform_device *dev) sp->info = dev_get_platdata(&dev->dev); /* setup spi bitbang adaptor */ - sp->bitbang.master = spi_master_get(master); + sp->bitbang.master = master; sp->bitbang.master->bus_num = sp->info->bus_num; sp->bitbang.master->num_chipselect = sp->info->num_chipselect; sp->bitbang.chipselect = sh_sci_spi_chipselect; diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index a1f21b74773..592b4aff651 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -632,7 +632,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) if (ret) goto free_master; - sspi->bitbang.master = spi_master_get(master); + sspi->bitbang.master = master; sspi->bitbang.chipselect = spi_sirfsoc_chipselect; sspi->bitbang.setup_transfer = spi_sirfsoc_setup_transfer; sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer; diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 145dd435483..9146bb3c248 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -182,6 +182,7 @@ struct tegra_spi_data { u32 cur_speed; struct spi_device *cur_spi; + struct spi_device *cs_control; unsigned cur_pos; unsigned cur_len; unsigned words_per_32bit; @@ -267,7 +268,7 @@ static unsigned tegra_spi_calculate_curr_xfer_param( unsigned max_len; unsigned total_fifo_words; - tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1; + tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8); if (bits_per_word == 8 || bits_per_word == 16) { tspi->is_packed = 1; @@ -676,15 +677,12 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } -static int tegra_spi_start_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg, - bool is_single_xfer) +static unsigned long tegra_spi_setup_transfer_one(struct spi_device *spi, + struct spi_transfer *t, bool is_first_of_msg) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); u32 speed = t->speed_hz; u8 bits_per_word = t->bits_per_word; - unsigned total_fifo_words; - int ret; unsigned long command1; int req_mode; @@ -698,7 +696,6 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, tspi->cur_rx_pos = 0; tspi->cur_tx_pos = 0; tspi->curr_xfer = t; - total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); if (is_first_of_msg) { tegra_spi_clear_status(tspi); @@ -717,7 +714,12 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, else if (req_mode == SPI_MODE_3) command1 |= SPI_CONTROL_MODE_3; - tegra_spi_writel(tspi, command1, SPI_COMMAND1); + if (tspi->cs_control) { + if (tspi->cs_control != spi) + tegra_spi_writel(tspi, command1, SPI_COMMAND1); + tspi->cs_control = NULL; + } else + tegra_spi_writel(tspi, command1, SPI_COMMAND1); command1 |= SPI_CS_SW_HW; if (spi->mode & SPI_CS_HIGH) @@ -732,6 +734,18 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, command1 |= SPI_BIT_LENGTH(bits_per_word - 1); } + return command1; +} + +static int tegra_spi_start_transfer_one(struct spi_device *spi, + struct spi_transfer *t, unsigned long command1) +{ + struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + unsigned total_fifo_words; + int ret; + + total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); + if (tspi->is_packed) command1 |= SPI_PACKED; @@ -803,29 +817,50 @@ static int tegra_spi_setup(struct spi_device *spi) return 0; } +static void tegra_spi_transfer_delay(int delay) +{ + if (!delay) + return; + + if (delay >= 1000) + mdelay(delay / 1000); + + udelay(delay % 1000); +} + static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { bool is_first_msg = true; - int single_xfer; struct tegra_spi_data *tspi = spi_master_get_devdata(master); struct spi_transfer *xfer; struct spi_device *spi = msg->spi; int ret; + bool skip = false; msg->status = 0; msg->actual_length = 0; - single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { + unsigned long cmd1; + INIT_COMPLETION(tspi->xfer_completion); - ret = tegra_spi_start_transfer_one(spi, xfer, - is_first_msg, single_xfer); + + cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); + + if (!xfer->len) { + ret = 0; + skip = true; + goto complete_xfer; + } + + ret = tegra_spi_start_transfer_one(spi, xfer, cmd1); if (ret < 0) { dev_err(tspi->dev, "spi can not start transfer, err %d\n", ret); - goto exit; + goto complete_xfer; } + is_first_msg = false; ret = wait_for_completion_timeout(&tspi->xfer_completion, SPI_DMA_TIMEOUT); @@ -833,24 +868,40 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, dev_err(tspi->dev, "spi trasfer timeout, err %d\n", ret); ret = -EIO; - goto exit; + goto complete_xfer; } if (tspi->tx_status || tspi->rx_status) { dev_err(tspi->dev, "Error in Transfer\n"); ret = -EIO; - goto exit; + goto complete_xfer; } msg->actual_length += xfer->len; - if (xfer->cs_change && xfer->delay_usecs) { + +complete_xfer: + if (ret < 0 || skip) { tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); - udelay(xfer->delay_usecs); + tegra_spi_transfer_delay(xfer->delay_usecs); + goto exit; + } else if (msg->transfers.prev == &xfer->transfer_list) { + /* This is the last transfer in message */ + if (xfer->cs_change) + tspi->cs_control = spi; + else { + tegra_spi_writel(tspi, tspi->def_command1_reg, + SPI_COMMAND1); + tegra_spi_transfer_delay(xfer->delay_usecs); + } + } else if (xfer->cs_change) { + tegra_spi_writel(tspi, tspi->def_command1_reg, + SPI_COMMAND1); + tegra_spi_transfer_delay(xfer->delay_usecs); } + } ret = 0; exit: - tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); msg->status = ret; spi_finalize_current_message(master); return ret; @@ -1115,7 +1166,7 @@ static int tegra_spi_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); master->dev.of_node = pdev->dev.of_node; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "can not register to master err %d\n", ret); goto exit_pm_disable; @@ -1142,7 +1193,6 @@ static int tegra_spi_remove(struct platform_device *pdev) struct tegra_spi_data *tspi = spi_master_get_devdata(master); free_irq(tspi->irq, tspi); - spi_unregister_master(master); if (tspi->tx_dma_chan) tegra_spi_deinit_dma_param(tspi, false); diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 1d814dc6e00..79be8ce6a9d 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -173,7 +173,7 @@ static unsigned tegra_sflash_calculate_curr_xfer_param( unsigned remain_len = t->len - tsd->cur_pos; unsigned max_word; - tsd->bytes_per_word = (t->bits_per_word - 1) / 8 + 1; + tsd->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8); max_word = remain_len / tsd->bytes_per_word; if (max_word > SPI_FIFO_DEPTH) max_word = SPI_FIFO_DEPTH; @@ -529,7 +529,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); master->dev.of_node = pdev->dev.of_node; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "can not register to master err %d\n", ret); goto exit_pm_disable; @@ -553,7 +553,6 @@ static int tegra_sflash_remove(struct platform_device *pdev) struct tegra_sflash_data *tsd = spi_master_get_devdata(master); free_irq(tsd->irq, tsd); - spi_unregister_master(master); pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index c70353672a2..af0a67886ae 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -278,12 +278,12 @@ static unsigned tegra_slink_calculate_curr_xfer_param( { unsigned remain_len = t->len - tspi->cur_pos; unsigned max_word; - unsigned bits_per_word ; + unsigned bits_per_word; unsigned max_len; unsigned total_fifo_words; bits_per_word = t->bits_per_word; - tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1; + tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8); if (bits_per_word == 8 || bits_per_word == 16) { tspi->is_packed = 1; @@ -707,8 +707,7 @@ static void tegra_slink_deinit_dma_param(struct tegra_slink_data *tspi, } static int tegra_slink_start_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg, - bool is_single_xfer) + struct spi_transfer *t) { struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master); u32 speed; @@ -732,32 +731,12 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, tspi->curr_xfer = t; total_fifo_words = tegra_slink_calculate_curr_xfer_param(spi, tspi, t); - if (is_first_of_msg) { - tegra_slink_clear_status(tspi); + command = tspi->command_reg; + command &= ~SLINK_BIT_LENGTH(~0); + command |= SLINK_BIT_LENGTH(bits_per_word - 1); - command = tspi->def_command_reg; - command |= SLINK_BIT_LENGTH(bits_per_word - 1); - command |= SLINK_CS_SW | SLINK_CS_VALUE; - - command2 = tspi->def_command2_reg; - command2 |= SLINK_SS_EN_CS(spi->chip_select); - - command &= ~SLINK_MODES; - if (spi->mode & SPI_CPHA) - command |= SLINK_CK_SDA; - - if (spi->mode & SPI_CPOL) - command |= SLINK_IDLE_SCLK_DRIVE_HIGH; - else - command |= SLINK_IDLE_SCLK_DRIVE_LOW; - } else { - command = tspi->command_reg; - command &= ~SLINK_BIT_LENGTH(~0); - command |= SLINK_BIT_LENGTH(bits_per_word - 1); - - command2 = tspi->command2_reg; - command2 &= ~(SLINK_RXEN | SLINK_TXEN); - } + command2 = tspi->command2_reg; + command2 &= ~(SLINK_RXEN | SLINK_TXEN); tegra_slink_writel(tspi, command, SLINK_COMMAND); tspi->command_reg = command; @@ -824,58 +803,72 @@ static int tegra_slink_setup(struct spi_device *spi) return 0; } -static int tegra_slink_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static int tegra_slink_prepare_message(struct spi_master *master, + struct spi_message *msg) { - bool is_first_msg = true; - int single_xfer; struct tegra_slink_data *tspi = spi_master_get_devdata(master); - struct spi_transfer *xfer; struct spi_device *spi = msg->spi; - int ret; - msg->status = 0; - msg->actual_length = 0; + tegra_slink_clear_status(tspi); - single_xfer = list_is_singular(&msg->transfers); - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - INIT_COMPLETION(tspi->xfer_completion); - ret = tegra_slink_start_transfer_one(spi, xfer, - is_first_msg, single_xfer); - if (ret < 0) { - dev_err(tspi->dev, - "spi can not start transfer, err %d\n", ret); - goto exit; - } - is_first_msg = false; - ret = wait_for_completion_timeout(&tspi->xfer_completion, - SLINK_DMA_TIMEOUT); - if (WARN_ON(ret == 0)) { - dev_err(tspi->dev, - "spi trasfer timeout, err %d\n", ret); - ret = -EIO; - goto exit; - } + tspi->command_reg = tspi->def_command_reg; + tspi->command_reg |= SLINK_CS_SW | SLINK_CS_VALUE; - if (tspi->tx_status || tspi->rx_status) { - dev_err(tspi->dev, "Error in Transfer\n"); - ret = -EIO; - goto exit; - } - msg->actual_length += xfer->len; - if (xfer->cs_change && xfer->delay_usecs) { - tegra_slink_writel(tspi, tspi->def_command_reg, - SLINK_COMMAND); - udelay(xfer->delay_usecs); - } + tspi->command2_reg = tspi->def_command2_reg; + tspi->command2_reg |= SLINK_SS_EN_CS(spi->chip_select); + + tspi->command_reg &= ~SLINK_MODES; + if (spi->mode & SPI_CPHA) + tspi->command_reg |= SLINK_CK_SDA; + + if (spi->mode & SPI_CPOL) + tspi->command_reg |= SLINK_IDLE_SCLK_DRIVE_HIGH; + else + tspi->command_reg |= SLINK_IDLE_SCLK_DRIVE_LOW; + + return 0; +} + +static int tegra_slink_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct tegra_slink_data *tspi = spi_master_get_devdata(master); + int ret; + + INIT_COMPLETION(tspi->xfer_completion); + ret = tegra_slink_start_transfer_one(spi, xfer); + if (ret < 0) { + dev_err(tspi->dev, + "spi can not start transfer, err %d\n", ret); + return ret; } - ret = 0; -exit: + + ret = wait_for_completion_timeout(&tspi->xfer_completion, + SLINK_DMA_TIMEOUT); + if (WARN_ON(ret == 0)) { + dev_err(tspi->dev, + "spi trasfer timeout, err %d\n", ret); + return -EIO; + } + + if (tspi->tx_status) + return tspi->tx_status; + if (tspi->rx_status) + return tspi->rx_status; + + return 0; +} + +static int tegra_slink_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct tegra_slink_data *tspi = spi_master_get_devdata(master); + tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); - msg->status = ret; - spi_finalize_current_message(master); - return ret; + + return 0; } static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi) @@ -1078,7 +1071,9 @@ static int tegra_slink_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_slink_setup; - master->transfer_one_message = tegra_slink_transfer_one_message; + master->prepare_message = tegra_slink_prepare_message; + master->transfer_one = tegra_slink_transfer_one; + master->unprepare_message = tegra_slink_unprepare_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; @@ -1164,7 +1159,7 @@ static int tegra_slink_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); master->dev.of_node = pdev->dev.of_node; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "can not register to master err %d\n", ret); goto exit_pm_disable; @@ -1191,7 +1186,6 @@ static int tegra_slink_remove(struct platform_device *pdev) struct tegra_slink_data *tspi = spi_master_get_devdata(master); free_irq(tspi->irq, tspi); - spi_unregister_master(master); if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index e12d962a289..0b71270fbf6 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -41,9 +41,6 @@ struct ti_qspi_regs { struct ti_qspi { struct completion transfer_complete; - /* IRQ synchronization */ - spinlock_t lock; - /* list synchronization */ struct mutex list_lock; @@ -57,7 +54,6 @@ struct ti_qspi { u32 spi_max_frequency; u32 cmd; u32 dc; - u32 stat; }; #define QSPI_PID (0x0) @@ -397,13 +393,12 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id) { struct ti_qspi *qspi = dev_id; u16 int_stat; + u32 stat; irqreturn_t ret = IRQ_HANDLED; - spin_lock(&qspi->lock); - int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); - qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); if (!int_stat) { dev_dbg(qspi->dev, "No IRQ triggered\n"); @@ -411,35 +406,14 @@ static irqreturn_t ti_qspi_isr(int irq, void *dev_id) goto out; } - ret = IRQ_WAKE_THREAD; - - ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_STATUS_ENABLED_CLEAR); - + if (stat & WC) + complete(&qspi->transfer_complete); out: - spin_unlock(&qspi->lock); - return ret; } -static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id) -{ - struct ti_qspi *qspi = dev_id; - unsigned long flags; - - spin_lock_irqsave(&qspi->lock, flags); - - if (qspi->stat & WC) - complete(&qspi->transfer_complete); - - spin_unlock_irqrestore(&qspi->lock, flags); - - ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); - - return IRQ_HANDLED; -} - static int ti_qspi_runtime_resume(struct device *dev) { struct ti_qspi *qspi; @@ -472,7 +446,7 @@ static int ti_qspi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; - master->mode_bits = SPI_CPOL | SPI_CPHA; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; master->bus_num = -1; master->flags = SPI_MASTER_HALF_DUPLEX; @@ -499,7 +473,6 @@ static int ti_qspi_probe(struct platform_device *pdev) return irq; } - spin_lock_init(&qspi->lock); mutex_init(&qspi->list_lock); qspi->base = devm_ioremap_resource(&pdev->dev, r); @@ -508,8 +481,7 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } - ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr, - ti_qspi_threaded_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, dev_name(&pdev->dev), qspi); if (ret < 0) { dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", @@ -532,7 +504,7 @@ static int ti_qspi_probe(struct platform_device *pdev) if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) qspi->spi_max_frequency = max_freq; - ret = spi_register_master(master); + ret = devm_spi_register_master(&pdev->dev, master); if (ret) goto free_master; @@ -547,7 +519,7 @@ static int ti_qspi_remove(struct platform_device *pdev) { struct ti_qspi *qspi = platform_get_drvdata(pdev); - spi_unregister_master(qspi->master); + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); return 0; } @@ -558,7 +530,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = { static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, - .remove = ti_qspi_remove, + .remove = ti_qspi_remove, .driver = { .name = "ti,dra7xxx-qspi", .owner = THIS_MODULE, diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index eaeeed51bbb..446131308ac 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -506,8 +506,8 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) goto err_out; } - dev_dbg(&pspi->dev, "%s Transfer List not empty. " - "Transfer Speed is set.\n", __func__); + dev_dbg(&pspi->dev, + "%s Transfer List not empty. Transfer Speed is set.\n", __func__); spin_lock_irqsave(&data->lock, flags); /* validate Tx/Rx buffers and Transfer length */ @@ -526,8 +526,9 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) goto err_return_spinlock; } - dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length" - " valid\n", __func__); + dev_dbg(&pspi->dev, + "%s Tx/Rx buffer valid. Transfer length valid\n", + __func__); /* if baud rate has been specified validate the same */ if (transfer->speed_hz > PCH_MAX_BAUDRATE) @@ -1181,8 +1182,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) spin_lock(&data->lock); /* check if suspend has been initiated;if yes flush queue */ if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) { - dev_dbg(&data->master->dev, "%s suspend/remove initiated," - "flushing queue\n", __func__); + dev_dbg(&data->master->dev, + "%s suspend/remove initiated, flushing queue\n", __func__); list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { pmsg->status = -EIO; @@ -1410,13 +1411,13 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) /* baseaddress + address offset) */ data->io_base_addr = pci_resource_start(board_dat->pdev, 1) + PCH_ADDRESS_SIZE * plat_dev->id; - data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0) + - PCH_ADDRESS_SIZE * plat_dev->id; + data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0); if (!data->io_remap_addr) { dev_err(&plat_dev->dev, "%s pci_iomap failed\n", __func__); ret = -ENOMEM; goto err_pci_iomap; } + data->io_remap_addr += PCH_ADDRESS_SIZE * plat_dev->id; dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p\n", plat_dev->id, data->io_remap_addr); diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 7c6d15766c7..637cce2b8bd 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -177,7 +177,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m) | 0x08, TXx9_SPCR0); - list_for_each_entry (t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) { const void *txbuf = t->tx_buf; void *rxbuf = t->rx_buf; u32 data; @@ -308,7 +308,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) m->actual_length = 0; /* check each transfer's parameters */ - list_for_each_entry (t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) { u32 speed_hz = t->speed_hz ? : spi->max_speed_hz; u8 bits_per_word = t->bits_per_word; @@ -406,7 +406,7 @@ static int txx9spi_probe(struct platform_device *dev) master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); - ret = spi_register_master(master); + ret = devm_spi_register_master(&dev->dev, master); if (ret) goto exit; return 0; @@ -428,11 +428,9 @@ static int txx9spi_remove(struct platform_device *dev) struct spi_master *master = spi_master_get(platform_get_drvdata(dev)); struct txx9spi *c = spi_master_get_devdata(master); - spi_unregister_master(master); destroy_workqueue(c->workqueue); clk_disable(c->clk); clk_put(c->clk); - spi_master_put(master); return 0; } @@ -440,6 +438,7 @@ static int txx9spi_remove(struct platform_device *dev) MODULE_ALIAS("platform:spi_txx9"); static struct platform_driver txx9spi_driver = { + .probe = txx9spi_probe, .remove = txx9spi_remove, .driver = { .name = "spi_txx9", @@ -449,7 +448,7 @@ static struct platform_driver txx9spi_driver = { static int __init txx9spi_init(void) { - return platform_driver_probe(&txx9spi_driver, txx9spi_probe); + return platform_driver_register(&txx9spi_driver); } subsys_initcall(txx9spi_init); diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 0bf1b2c457a..ec3a83f52ea 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -372,7 +372,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA; xspi = spi_master_get_devdata(master); - xspi->bitbang.master = spi_master_get(master); + xspi->bitbang.master = master; xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9e039c60c06..8d05accf706 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -39,6 +39,9 @@ #include <linux/ioport.h> #include <linux/acpi.h> +#define CREATE_TRACE_POINTS +#include <trace/events/spi.h> + static void spidev_release(struct device *dev) { struct spi_device *spi = to_spi_device(dev); @@ -58,11 +61,13 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias); } +static DEVICE_ATTR_RO(modalias); -static struct device_attribute spi_dev_attrs[] = { - __ATTR_RO(modalias), - __ATTR_NULL, +static struct attribute *spi_dev_attrs[] = { + &dev_attr_modalias.attr, + NULL, }; +ATTRIBUTE_GROUPS(spi_dev); /* modalias support makes "modprobe $MODALIAS" new-style hotplug work, * and the sysfs version makes coldplug work too. @@ -229,7 +234,7 @@ static const struct dev_pm_ops spi_pm = { struct bus_type spi_bus_type = { .name = "spi", - .dev_attrs = spi_dev_attrs, + .dev_groups = spi_dev_groups, .match = spi_match_device, .uevent = spi_uevent, .pm = &spi_pm, @@ -323,7 +328,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master) if (!spi_master_get(master)) return NULL; - spi = kzalloc(sizeof *spi, GFP_KERNEL); + spi = kzalloc(sizeof(*spi), GFP_KERNEL); if (!spi) { dev_err(dev, "cannot alloc spi_device\n"); spi_master_put(master); @@ -523,6 +528,95 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) /*-------------------------------------------------------------------------*/ +static void spi_set_cs(struct spi_device *spi, bool enable) +{ + if (spi->mode & SPI_CS_HIGH) + enable = !enable; + + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, !enable); + else if (spi->master->set_cs) + spi->master->set_cs(spi, !enable); +} + +/* + * spi_transfer_one_message - Default implementation of transfer_one_message() + * + * This is a standard implementation of transfer_one_message() for + * drivers which impelment a transfer_one() operation. It provides + * standard handling of delays and chip select management. + */ +static int spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) +{ + struct spi_transfer *xfer; + bool cur_cs = true; + bool keep_cs = false; + int ret = 0; + + spi_set_cs(msg->spi, true); + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + trace_spi_transfer_start(msg, xfer); + + INIT_COMPLETION(master->xfer_completion); + + ret = master->transfer_one(master, msg->spi, xfer); + if (ret < 0) { + dev_err(&msg->spi->dev, + "SPI transfer failed: %d\n", ret); + goto out; + } + + if (ret > 0) + wait_for_completion(&master->xfer_completion); + + trace_spi_transfer_stop(msg, xfer); + + if (msg->status != -EINPROGRESS) + goto out; + + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + + if (xfer->cs_change) { + if (list_is_last(&xfer->transfer_list, + &msg->transfers)) { + keep_cs = true; + } else { + cur_cs = !cur_cs; + spi_set_cs(msg->spi, cur_cs); + } + } + + msg->actual_length += xfer->len; + } + +out: + if (ret != 0 || !keep_cs) + spi_set_cs(msg->spi, false); + + if (msg->status == -EINPROGRESS) + msg->status = ret; + + spi_finalize_current_message(master); + + return ret; +} + +/** + * spi_finalize_current_transfer - report completion of a transfer + * + * Called by SPI drivers using the core transfer_one_message() + * implementation to notify it that the current interrupt driven + * transfer has finised and the next one may be scheduled. + */ +void spi_finalize_current_transfer(struct spi_master *master) +{ + complete(&master->xfer_completion); +} +EXPORT_SYMBOL_GPL(spi_finalize_current_transfer); + /** * spi_pump_messages - kthread work function which processes spi message queue * @work: pointer to kthread work struct contained in the master struct @@ -557,6 +651,7 @@ static void spi_pump_messages(struct kthread_work *work) pm_runtime_mark_last_busy(master->dev.parent); pm_runtime_put_autosuspend(master->dev.parent); } + trace_spi_master_idle(master); return; } @@ -585,6 +680,9 @@ static void spi_pump_messages(struct kthread_work *work) } } + if (!was_busy) + trace_spi_master_busy(master); + if (!was_busy && master->prepare_transfer_hardware) { ret = master->prepare_transfer_hardware(master); if (ret) { @@ -597,6 +695,20 @@ static void spi_pump_messages(struct kthread_work *work) } } + trace_spi_message_start(master->cur_msg); + + if (master->prepare_message) { + ret = master->prepare_message(master, master->cur_msg); + if (ret) { + dev_err(&master->dev, + "failed to prepare message: %d\n", ret); + master->cur_msg->status = ret; + spi_finalize_current_message(master); + return; + } + master->cur_msg_prepared = true; + } + ret = master->transfer_one_message(master, master->cur_msg); if (ret) { dev_err(&master->dev, @@ -678,6 +790,7 @@ void spi_finalize_current_message(struct spi_master *master) { struct spi_message *mesg; unsigned long flags; + int ret; spin_lock_irqsave(&master->queue_lock, flags); mesg = master->cur_msg; @@ -686,9 +799,20 @@ void spi_finalize_current_message(struct spi_master *master) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); + if (master->cur_msg_prepared && master->unprepare_message) { + ret = master->unprepare_message(master, mesg); + if (ret) { + dev_err(&master->dev, + "failed to unprepare message: %d\n", ret); + } + } + master->cur_msg_prepared = false; + mesg->state = NULL; if (mesg->complete) mesg->complete(mesg->context); + + trace_spi_message_done(mesg); } EXPORT_SYMBOL_GPL(spi_finalize_current_message); @@ -803,6 +927,8 @@ static int spi_master_initialize_queue(struct spi_master *master) master->queued = true; master->transfer = spi_queued_transfer; + if (!master->transfer_one_message) + master->transfer_one_message = spi_transfer_one_message; /* Initialize and start queue */ ret = spi_init_queue(master); @@ -838,10 +964,8 @@ static void of_register_spi_devices(struct spi_master *master) { struct spi_device *spi; struct device_node *nc; - const __be32 *prop; - char modalias[SPI_NAME_SIZE + 4]; int rc; - int len; + u32 value; if (!master->dev.of_node) return; @@ -866,14 +990,14 @@ static void of_register_spi_devices(struct spi_master *master) } /* Device address */ - prop = of_get_property(nc, "reg", &len); - if (!prop || len < sizeof(*prop)) { - dev_err(&master->dev, "%s has no 'reg' property\n", - nc->full_name); + rc = of_property_read_u32(nc, "reg", &value); + if (rc) { + dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", + nc->full_name, rc); spi_dev_put(spi); continue; } - spi->chip_select = be32_to_cpup(prop); + spi->chip_select = value; /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) @@ -886,55 +1010,53 @@ static void of_register_spi_devices(struct spi_master *master) spi->mode |= SPI_3WIRE; /* Device DUAL/QUAD mode */ - prop = of_get_property(nc, "spi-tx-bus-width", &len); - if (prop && len == sizeof(*prop)) { - switch (be32_to_cpup(prop)) { - case SPI_NBITS_SINGLE: + if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { + switch (value) { + case 1: break; - case SPI_NBITS_DUAL: + case 2: spi->mode |= SPI_TX_DUAL; break; - case SPI_NBITS_QUAD: + case 4: spi->mode |= SPI_TX_QUAD; break; default: dev_err(&master->dev, "spi-tx-bus-width %d not supported\n", - be32_to_cpup(prop)); + value); spi_dev_put(spi); continue; } } - prop = of_get_property(nc, "spi-rx-bus-width", &len); - if (prop && len == sizeof(*prop)) { - switch (be32_to_cpup(prop)) { - case SPI_NBITS_SINGLE: + if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) { + switch (value) { + case 1: break; - case SPI_NBITS_DUAL: + case 2: spi->mode |= SPI_RX_DUAL; break; - case SPI_NBITS_QUAD: + case 4: spi->mode |= SPI_RX_QUAD; break; default: dev_err(&master->dev, "spi-rx-bus-width %d not supported\n", - be32_to_cpup(prop)); + value); spi_dev_put(spi); continue; } } /* Device speed */ - prop = of_get_property(nc, "spi-max-frequency", &len); - if (!prop || len < sizeof(*prop)) { - dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n", - nc->full_name); + rc = of_property_read_u32(nc, "spi-max-frequency", &value); + if (rc) { + dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n", + nc->full_name, rc); spi_dev_put(spi); continue; } - spi->max_speed_hz = be32_to_cpup(prop); + spi->max_speed_hz = value; /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); @@ -944,9 +1066,7 @@ static void of_register_spi_devices(struct spi_master *master) spi->dev.of_node = nc; /* Register the new device */ - snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX, - spi->modalias); - request_module(modalias); + request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias); rc = spi_add_device(spi); if (rc) { dev_err(&master->dev, "spi_device register error %s\n", @@ -1025,7 +1145,7 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return AE_OK; } - strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); + strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); if (spi_add_device(spi)) { dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", dev_name(&adev->dev)); @@ -1097,7 +1217,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) if (!dev) return NULL; - master = kzalloc(size + sizeof *master, GFP_KERNEL); + master = kzalloc(size + sizeof(*master), GFP_KERNEL); if (!master) return NULL; @@ -1122,7 +1242,7 @@ static int of_spi_register_master(struct spi_master *master) return 0; nb = of_gpio_named_count(np, "cs-gpios"); - master->num_chipselect = max(nb, (int)master->num_chipselect); + master->num_chipselect = max_t(int, nb, master->num_chipselect); /* Return error only for an incorrectly formed cs-gpios property */ if (nb == 0 || nb == -ENOENT) @@ -1209,6 +1329,7 @@ int spi_register_master(struct spi_master *master) spin_lock_init(&master->bus_lock_spinlock); mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; + init_completion(&master->xfer_completion); /* register the device, then userspace will see it. * registration fails if the bus ID is in use. @@ -1245,6 +1366,41 @@ done: } EXPORT_SYMBOL_GPL(spi_register_master); +static void devm_spi_unregister(struct device *dev, void *res) +{ + spi_unregister_master(*(struct spi_master **)res); +} + +/** + * dev_spi_register_master - register managed SPI master controller + * @dev: device managing SPI master + * @master: initialized master, originally from spi_alloc_master() + * Context: can sleep + * + * Register a SPI device as with spi_register_master() which will + * automatically be unregister + */ +int devm_spi_register_master(struct device *dev, struct spi_master *master) +{ + struct spi_master **ptr; + int ret; + + ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = spi_register_master(master); + if (ret != 0) { + *ptr = master; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_spi_register_master); + static int __unregister(struct device *dev, void *null) { spi_unregister_device(to_spi_device(dev)); @@ -1402,8 +1558,7 @@ int spi_setup(struct spi_device *spi) if (spi->master->setup) status = spi->master->setup(spi); - dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s" - "%u bits/w, %u Hz max --> %d\n", + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", @@ -1421,6 +1576,10 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) struct spi_master *master = spi->master; struct spi_transfer *xfer; + message->spi = spi; + + trace_spi_message_submit(message); + if (list_empty(&message->transfers)) return -EINVAL; if (!message->complete) @@ -1520,7 +1679,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) } } - message->spi = spi; message->status = -EINPROGRESS; return master->transfer(spi, message); } @@ -1762,7 +1920,7 @@ int spi_bus_unlock(struct spi_master *master) EXPORT_SYMBOL_GPL(spi_bus_unlock); /* portable code must never pass more than 32 bytes */ -#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES) +#define SPI_BUFSIZ max(32, SMP_CACHE_BYTES) static u8 *buf; @@ -1811,7 +1969,7 @@ int spi_write_then_read(struct spi_device *spi, } spi_message_init(&message); - memset(x, 0, sizeof x); + memset(x, 0, sizeof(x)); if (n_tx) { x[0].len = n_tx; spi_message_add_tail(&x[0], &message); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index ca5bcfe874d..d7c6e36021e 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -37,7 +37,7 @@ #include <linux/spi/spi.h> #include <linux/spi/spidev.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> /* @@ -206,9 +206,9 @@ spidev_write(struct file *filp, const char __user *buf, mutex_lock(&spidev->buf_lock); missing = copy_from_user(spidev->buffer, buf, count); - if (missing == 0) { + if (missing == 0) status = spidev_sync_write(spidev, count); - } else + else status = -EFAULT; mutex_unlock(&spidev->buf_lock); @@ -629,7 +629,6 @@ static int spidev_remove(struct spi_device *spi) /* make sure ops on existing fds can abort cleanly */ spin_lock_irq(&spidev->spi_lock); spidev->spi = NULL; - spi_set_drvdata(spi, NULL); spin_unlock_irq(&spidev->spi_lock); /* prevent new opens */ diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 6200335d12f..00492cad7c5 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -86,7 +86,7 @@ static int ade7753_spi_read_reg_16(struct device *dev, struct ade7753_state *st = iio_priv(indio_dev); ssize_t ret; - ret = spi_w8r16(st->us, ADE7753_READ_REG(reg_address)); + ret = spi_w8r16be(st->us, ADE7753_READ_REG(reg_address)); if (ret < 0) { dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -94,7 +94,6 @@ static int ade7753_spi_read_reg_16(struct device *dev, } *val = ret; - *val = be16_to_cpup(val); return 0; } diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 2e046f6e4fb..e0aa13ab365 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -86,7 +86,7 @@ static int ade7754_spi_read_reg_16(struct device *dev, struct ade7754_state *st = iio_priv(indio_dev); int ret; - ret = spi_w8r16(st->us, ADE7754_READ_REG(reg_address)); + ret = spi_w8r16be(st->us, ADE7754_READ_REG(reg_address)); if (ret < 0) { dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -94,7 +94,6 @@ static int ade7754_spi_read_reg_16(struct device *dev, } *val = ret; - *val = be16_to_cpup(val); return 0; } diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index 145f896aae2..ea0c9debf8b 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -86,7 +86,7 @@ static int ade7759_spi_read_reg_16(struct device *dev, struct ade7759_state *st = iio_priv(indio_dev); int ret; - ret = spi_w8r16(st->us, ADE7759_READ_REG(reg_address)); + ret = spi_w8r16be(st->us, ADE7759_READ_REG(reg_address)); if (ret < 0) { dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X", reg_address); @@ -94,7 +94,6 @@ static int ade7759_spi_read_reg_16(struct device *dev, } *val = ret; - *val = be16_to_cpup(val); return 0; } diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index af08e677b60..f6bc4c91ab3 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -67,7 +67,7 @@ #include <linux/delay.h> #include <linux/poll.h> #include <linux/platform_device.h> - +#include <linux/gpio.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/fcntl.h> @@ -321,7 +321,7 @@ static void on(void) * status LED and ground */ if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW); + gpio_set_value(NSLU2_LED_GRN, 0); return; } #endif @@ -335,7 +335,7 @@ static void off(void) { #ifdef CONFIG_LIRC_SERIAL_NSLU2 if (type == LIRC_NSLU2) { - gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH); + gpio_set_value(NSLU2_LED_GRN, 1); return; } #endif @@ -839,6 +839,16 @@ static int lirc_serial_probe(struct platform_device *dev) { int i, nlow, nhigh, result; +#ifdef CONFIG_LIRC_SERIAL_NSLU2 + /* This GPIO is used for a LED on the NSLU2 */ + result = devm_gpio_request(dev, NSLU2_LED_GRN, "lirc-serial"); + if (result) + return result; + result = gpio_direction_output(NSLU2_LED_GRN, 0); + if (result) + return result; +#endif + result = request_irq(irq, irq_handler, (share_irq ? IRQF_SHARED : 0), LIRC_DRIVER_NAME, (void *)&hardware); diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 9bffcec5ad8..0419b69e270 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -32,6 +32,7 @@ #include <linux/poll.h> #include <asm/epapr_hcalls.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/console.h> diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index cd69b48f6df..6496872e2e4 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -329,7 +329,7 @@ static void udbg_init_opal_common(void) void __init hvc_opal_init_early(void) { struct device_node *stdout_node = NULL; - const u32 *termno; + const __be32 *termno; const char *name = NULL; const struct hv_ops *ops; u32 index; @@ -371,7 +371,7 @@ void __init hvc_opal_init_early(void) if (!stdout_node) return; termno = of_get_property(stdout_node, "reg", NULL); - index = termno ? *termno : 0; + index = termno ? be32_to_cpup(termno) : 0; if (index >= MAX_NR_HVC_CONSOLES) return; hvc_opal_privs[index] = &hvc_opal_boot_priv; diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index ac2767100df..347050ea414 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -9,7 +9,7 @@ static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet) { - packet->seqno = atomic_inc_return(&pv->seqno); + packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno)); /* Assumes that always succeeds, works in practice */ return pv->put_chars(pv->termno, (char *)packet, packet->len); @@ -28,7 +28,7 @@ static void hvsi_start_handshake(struct hvsi_priv *pv) /* Send version query */ q.hdr.type = VS_QUERY_PACKET_HEADER; q.hdr.len = sizeof(struct hvsi_query); - q.verb = VSV_SEND_VERSION_NUMBER; + q.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER); hvsi_send_packet(pv, &q.hdr); } @@ -40,7 +40,7 @@ static int hvsi_send_close(struct hvsi_priv *pv) ctrl.hdr.type = VS_CONTROL_PACKET_HEADER; ctrl.hdr.len = sizeof(struct hvsi_control); - ctrl.verb = VSV_CLOSE_PROTOCOL; + ctrl.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL); return hvsi_send_packet(pv, &ctrl.hdr); } @@ -69,14 +69,14 @@ static void hvsi_got_control(struct hvsi_priv *pv) { struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf; - switch (pkt->verb) { + switch (be16_to_cpu(pkt->verb)) { case VSV_CLOSE_PROTOCOL: /* We restart the handshaking */ hvsi_start_handshake(pv); break; case VSV_MODEM_CTL_UPDATE: /* Transition of carrier detect */ - hvsi_cd_change(pv, pkt->word & HVSI_TSCD); + hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD); break; } } @@ -87,7 +87,7 @@ static void hvsi_got_query(struct hvsi_priv *pv) struct hvsi_query_response r; /* We only handle version queries */ - if (pkt->verb != VSV_SEND_VERSION_NUMBER) + if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER) return; pr_devel("HVSI@%x: Got version query, sending response...\n", @@ -96,7 +96,7 @@ static void hvsi_got_query(struct hvsi_priv *pv) /* Send version response */ r.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER; r.hdr.len = sizeof(struct hvsi_query_response); - r.verb = VSV_SEND_VERSION_NUMBER; + r.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER); r.u.version = HVSI_VERSION; r.query_seqno = pkt->hdr.seqno; hvsi_send_packet(pv, &r.hdr); @@ -112,7 +112,7 @@ static void hvsi_got_response(struct hvsi_priv *pv) switch(r->verb) { case VSV_SEND_MODEM_CTL_STATUS: - hvsi_cd_change(pv, r->u.mctrl_word & HVSI_TSCD); + hvsi_cd_change(pv, be32_to_cpu(r->u.mctrl_word) & HVSI_TSCD); pv->mctrl_update = 1; break; } @@ -265,8 +265,7 @@ int hvsilib_read_mctrl(struct hvsi_priv *pv) pv->mctrl_update = 0; q.hdr.type = VS_QUERY_PACKET_HEADER; q.hdr.len = sizeof(struct hvsi_query); - q.hdr.seqno = atomic_inc_return(&pv->seqno); - q.verb = VSV_SEND_MODEM_CTL_STATUS; + q.verb = cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS); rc = hvsi_send_packet(pv, &q.hdr); if (rc <= 0) { pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc); @@ -304,9 +303,9 @@ int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr) ctrl.hdr.type = VS_CONTROL_PACKET_HEADER, ctrl.hdr.len = sizeof(struct hvsi_control); - ctrl.verb = VSV_SET_MODEM_CTL; - ctrl.mask = HVSI_TSDTR; - ctrl.word = dtr ? HVSI_TSDTR : 0; + ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL); + ctrl.mask = cpu_to_be32(HVSI_TSDTR); + ctrl.word = cpu_to_be32(dtr ? HVSI_TSDTR : 0); return hvsi_send_packet(pv, &ctrl.hdr); } diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 1a535f70dc4..7d76214612c 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -41,6 +41,8 @@ #include <linux/bootmem.h> #include <linux/dma-mapping.h> #include <linux/fs_uart_pd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> @@ -1207,7 +1209,7 @@ static int cpm_uart_init_port(struct device_node *np, pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; spin_lock_init(&pinfo->port.lock); - pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + pinfo->port.irq = irq_of_parse_and_map(np, 0); if (pinfo->port.irq == NO_IRQ) { ret = -EINVAL; goto out_pram; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c index 18f79575894..527a969b095 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c @@ -45,6 +45,7 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <linux/of_address.h> #include "cpm_uart.h" diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 95917cefe14..481b781b26e 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -57,6 +57,8 @@ #include <linux/bitops.h> #include <linux/sysrq.h> #include <linux/mutex.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/sections.h> #include <asm/io.h> #include <asm/irq.h> diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 2fd1e178981..d569ca58bab 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -25,6 +25,8 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index f3bb363f1d4..807127d56fa 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -33,6 +33,7 @@ #include <linux/io.h> #include <linux/moduleparam.h> #include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> #include <linux/usb/ch9.h> diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 6cc5567bf9c..875d2fcc9e0 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -16,6 +16,8 @@ #include <linux/signal.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0b46542591f..0551c0af0fd 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -26,6 +26,8 @@ #include <linux/io.h> #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/slab.h> diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 75f5a1e2f01..81f3eba215c 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -14,6 +14,8 @@ */ #include <linux/signal.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <asm/prom.h> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 6dd72250111..b047ec58ac3 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -31,6 +31,8 @@ #include <linux/uaccess.h> #include <linux/vmalloc.h> #include <linux/spinlock.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <sysdev/fsl_soc.h> #include <linux/fsl-diu-fb.h> diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index f082ae55c0c..4f26bc28e60 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c @@ -3320,9 +3320,8 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) } #ifndef GETBITSTR -#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) -#define GENMASK(mask) BITMASK(1?mask,0?mask) -#define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) +#define GENBITSMASK(mask) GENMASK(1?mask,0?mask) +#define GETBITS(var,mask) (((var) & GENBITSMASK(mask)) >> (0?mask)) #define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) #endif diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c index d294f67d6f8..32c8fc5f7a5 100644 --- a/drivers/virt/fsl_hypervisor.c +++ b/drivers/virt/fsl_hypervisor.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/poll.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/reboot.h> #include <linux/uaccess.h> #include <linux/notifier.h> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d1d53f301de..6df632e0bb5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -418,8 +418,6 @@ config BFIN_WDT # FRV Architecture -# H8300 Architecture - # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6c5bb274d3c..8c7b8bcbbdc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -66,8 +66,6 @@ obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o # FRV Architecture -# H8300 Architecture - # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index 257cfbad21d..3755833430d 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -34,6 +34,7 @@ #include <linux/watchdog.h> #include <linux/fs.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/io.h> #include <linux/uaccess.h> diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c index 9dda2d08af9..8ced2561395 100644 --- a/drivers/watchdog/intel_scu_watchdog.c +++ b/drivers/watchdog/intel_scu_watchdog.c @@ -48,7 +48,7 @@ #include <linux/atomic.h> #include <asm/intel_scu_ipc.h> #include <asm/apb_timer.h> -#include <asm/mrst.h> +#include <asm/intel-mid.h> #include "intel_scu_watchdog.h" @@ -445,7 +445,7 @@ static int __init intel_scu_watchdog_init(void) * * If it isn't an intel MID device then it doesn't have this watchdog */ - if (!mrst_identify_cpu()) + if (!intel_mid_identify_cpu()) return -ENODEV; /* Check boot parameters to verify that their initial values */ diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index da2752063bb..d0ebebae607 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -24,6 +24,7 @@ #include <linux/kernel.h> #include <linux/timer.h> #include <linux/miscdevice.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/module.h> #include <linux/watchdog.h> diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c index 7d3d471f810..329bc60ad7a 100644 --- a/drivers/watchdog/pika_wdt.c +++ b/drivers/watchdog/pika_wdt.c @@ -22,6 +22,7 @@ #include <linux/bitops.h> #include <linux/uaccess.h> #include <linux/io.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #define DRV_NAME "PIKA-WDT" |