LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [v3, 3/7] powerpc: enable the relocatable support for the fsl booke 32bit kernel
From: Scott Wood @ 2014-01-09  0:02 UTC (permalink / raw)
  To: Kevin Hao; +Cc: linuxppc
In-Reply-To: <20140108024235.GA20739@pek-khao-d1.corp.ad.wrs.com>

On Wed, Jan 08, 2014 at 10:42:35AM +0800, Kevin Hao wrote:
> On Tue, Jan 07, 2014 at 05:46:04PM -0600, Scott Wood wrote:
> > Oh.  I think it'd be more readable to do "offset = start -
> > memstart_addr" and add offset instead of subtracting it.
> 
> Yes, I agree. The reason that I use "offset = memstart_addr - start" is that
> it seems "memstart_addr" is always greater than "start" when we are booting
> a kdump kernel with a kernel option like "crashkernel=64M@80M". :-)
> 
> > 
> > Also, offset should be phys_addr_t -- even if you don't expect to
> > support offsets greater than 4G on 32-bit, it's semantically the right
> > type to use.  Plus, "int" would break if this code were ever used with
> > 64-bit.
> 
> I thought about using phy_addr_t for the "offset" originally but gave it up
> for the following reasons:
>   * It will not be greater than 4G.
>   * We have to use the ugly #ifdef CONFIG_PHYS_64BIT in restore_to_as0().
>   * Need more registers for arguments for restore_to_as0().
> 
> Of course you can change it to phys_addr_t if you prefer.

Here's the diff I made when applying (also changed the subf in patch 9 to
add)

diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 71e08df..b1f7edc 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -1251,7 +1251,7 @@ _GLOBAL(switch_to_as1)
  * Restore to the address space 0 and also invalidate the tlb entry created
  * by switch_to_as1.
  * r3 - the tlb entry which should be invalidated
- * r4 - __pa(PAGE_OFFSET in AS0) - __pa(PAGE_OFFSET in AS1)
+ * r4 - __pa(PAGE_OFFSET in AS1) - __pa(PAGE_OFFSET in AS0)
  * r5 - device tree virtual address. If r4 is 0, r5 is ignored.
 */
 _GLOBAL(restore_to_as0)
@@ -1266,8 +1266,8 @@ _GLOBAL(restore_to_as0)
 	 * so we need calculate the right jump and device tree address based
 	 * on the offset passed by r4.
 	 */
-	subf	r9,r4,r9
-	subf	r5,r4,r5
+	add	r9,r9,r4
+	add	r5,r5,r4
 
 2:	mfmsr	r7
 	li	r8,(MSR_IS | MSR_DS)
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index ce0c7d7..95deb9fd 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -291,7 +291,8 @@ notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start)
 	 * and do a second relocation.
 	 */
 	if (start != memstart_addr) {
-		int n, offset = memstart_addr - start;
+		int n;
+		long offset = start - memstart_addr;
 
 		is_second_reloc = 1;
 		n = switch_to_as1();
@@ -299,7 +300,7 @@ notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start)
 		if (memstart_addr > start)
 			map_mem_in_cams(0x4000000, CONFIG_LOWMEM_CAM_NUM);
 		else
-			map_mem_in_cams_addr(start, PAGE_OFFSET - offset,
+			map_mem_in_cams_addr(start, PAGE_OFFSET + offset,
 					0x4000000, CONFIG_LOWMEM_CAM_NUM);
 		restore_to_as0(n, offset, __va(dt_ptr));
 		/* We should never reach here */

-Scott

^ permalink raw reply related

* Re: [PATCH] powerpc: add vr save/restore functions
From: Michael Ellerman @ 2014-01-09  0:09 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: linuxppc-dev
In-Reply-To: <87fvoypznh.fsf@igel.home>

On Wed, 2014-01-08 at 10:54 +0100, Andreas Schwab wrote:
> Michael Ellerman <michael@ellerman.id.au> writes:
> 
> > On Mon, 2013-12-30 at 15:31 +0100, Andreas Schwab wrote:
> >> GCC 4.8 now generates out-of-line vr save/restore functions when
> >> optimizing for size.  They are needed for the raid6 altivec support.
> >
> > It looks like they're identical for 32 & 64-bit ?
> 
> They use different temporary registers and calling conventions (no .opd
> for ppc64).

Yeah, sorry, you'd think I could spot the difference between r11 and r12.

cheers

^ permalink raw reply

* Re: [PATCH 02/12][v4] pci: fsl: add structure fsl_pci
From: Bjorn Helgaas @ 2014-01-09  0:12 UTC (permalink / raw)
  To: Scott Wood; +Cc: linux-pci, Minghuan Lian, linuxppc-dev, Zang Roy-R61911
In-Reply-To: <1389218288.25654.26.camel@snotra.buserror.net>

On Wed, Jan 08, 2014 at 03:58:08PM -0600, Scott Wood wrote:
> On Wed, 2014-01-08 at 13:01 +0800, Minghuan Lian wrote:
> > PowerPC uses structure pci_controller to describe PCI controller,
> > but ARM uses structure pci_sys_data. In order to support PowerPC
> > and ARM simultaneously, the patch adds a structure fsl_pci that
> > contains most of the members of the pci_controller and pci_sys_data.
> > Meanwhile, it defines a interface fsl_arch_sys_to_pci() which should
> > be implemented in architecture-specific PCI controller driver to
> > convert pci_controller or pci_sys_data to fsl_pci.
> > 
> > Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
> > ---
> > change log:
> > v4:
> > Added indirect type macro
> > v1-v3:
> > Derived from http://patchwork.ozlabs.org/patch/278965/
> > 
> > Based on upstream master.
> > Based on the discussion of RFC version here
> > http://patchwork.ozlabs.org/patch/274487/
> > 
> >  include/linux/fsl/pci-common.h | 48 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 48 insertions(+)
> 
> Same comments on this patchset as last time.

Minghuan, when you address Scott's comments, can you also add a
MAINTAINERS update?

Bjorn

^ permalink raw reply

* Re: [PATCH] slub: Don't throw away partial remote slabs if there is no local memory
From: Joonsoo Kim @ 2014-01-09  0:20 UTC (permalink / raw)
  To: Wanpeng Li
  Cc: cl, nacc, penberg, linux-mm, paulus, Anton Blanchard, mpm,
	linuxppc-dev
In-Reply-To: <52cbce84.aa71b60a.537c.ffffd9efSMTPIN_ADDED_BROKEN@mx.google.com>

On Tue, Jan 07, 2014 at 05:52:31PM +0800, Wanpeng Li wrote:
> On Tue, Jan 07, 2014 at 04:41:36PM +0900, Joonsoo Kim wrote:
> >On Tue, Jan 07, 2014 at 01:21:00PM +1100, Anton Blanchard wrote:

> >> Index: b/mm/slub.c
> >> ===================================================================
> >> --- a/mm/slub.c
> >> +++ b/mm/slub.c
> >> @@ -2278,10 +2278,17 @@ redo:
> >>  
> >>  	if (unlikely(!node_match(page, node))) {
> >>  		stat(s, ALLOC_NODE_MISMATCH);
> >> -		deactivate_slab(s, page, c->freelist);
> >> -		c->page = NULL;
> >> -		c->freelist = NULL;
> >> -		goto new_slab;
> >> +
> >> +		/*
> >> +		 * If the node contains no memory there is no point in trying
> >> +		 * to allocate a new node local slab
> >> +		 */
> >> +		if (node_spanned_pages(node)) {
> >> +			deactivate_slab(s, page, c->freelist);
> >> +			c->page = NULL;
> >> +			c->freelist = NULL;
> >> +			goto new_slab;
> >> +		}
> >>  	}
> >>  
> >>  	/*
> >
> >Hello,
> >
> >I think that we need more efforts to solve unbalanced node problem.
> >
> >With this patch, even if node of current cpu slab is not favorable to
> >unbalanced node, allocation would proceed and we would get the unintended memory.
> >
> >And there is one more problem. Even if we have some partial slabs on
> >compatible node, we would allocate new slab, because get_partial() cannot handle
> >this unbalance node case.
> >
> >To fix this correctly, how about following patch?
> >
> >Thanks.
> >
> >------------->8--------------------
> >diff --git a/mm/slub.c b/mm/slub.c
> >index c3eb3d3..a1f6dfa 100644
> >--- a/mm/slub.c
> >+++ b/mm/slub.c
> >@@ -1672,7 +1672,19 @@ static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
> > {
> >        void *object;
> >        int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
> >+       struct zonelist *zonelist;
> >+       struct zoneref *z;
> >+       struct zone *zone;
> >+       enum zone_type high_zoneidx = gfp_zone(flags);
> >
> >+       if (!node_present_pages(searchnode)) {
> >+               zonelist = node_zonelist(searchnode, flags);
> >+               for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
> >+                       searchnode = zone_to_nid(zone);
> >+                       if (node_present_pages(searchnode))
> >+                               break;
> >+               }
> >+       }
> 
> Why change searchnode instead of depending on fallback zones/nodes in 
> get_any_partial() to allocate partial slabs?
> 

If node != NUMA_NO_NODE, get_any_partial() isn't called.
That's why I change searchnode here instead of get_any_partial().

Thanks.

^ permalink raw reply

* [PATCH v4 1/3] powerpc: add barrier after writing kernel PTE
From: Scott Wood @ 2014-01-09  1:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood

There is no barrier between something like ioremap() writing to
a PTE, and returning the value to a caller that may then store the
pointer in a place that is visible to other CPUs.  Such callers
generally don't perform barriers of their own.

Even if callers of ioremap() and similar things did use barriers,
the most logical choise would be smp_wmb(), which is not
architecturally sufficient when BookE hardware tablewalk is used.  A
full sync is specified by the architecture.

For userspace mappings, OTOH, we generally already have an lwsync due
to locking, and if we occasionally take a spurious fault due to not
having a full sync with hardware tablewalk, it will not be fatal
because we will retry rather than oops.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
v4: no change

 arch/powerpc/mm/pgtable_32.c |  1 +
 arch/powerpc/mm/pgtable_64.c | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 5b96017..343a87f 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -299,6 +299,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
 		set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
 						     __pgprot(flags)));
 	}
+	smp_wmb();
 	return err;
 }
 
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 02e8681..7551382 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -153,6 +153,18 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
 		}
 #endif /* !CONFIG_PPC_MMU_NOHASH */
 	}
+
+#ifdef CONFIG_PPC_BOOK3E_64
+	/*
+	 * With hardware tablewalk, a sync is needed to ensure that
+	 * subsequent accesses see the PTE we just wrote.  Unlike userspace
+	 * mappings, we can't tolerate spurious faults, so make sure
+	 * the new PTE will be seen the first time.
+	 */
+	mb();
+#else
+	smp_wmb();
+#endif
 	return 0;
 }
 
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH v4 2/3] powerpc/e6500: TLB miss handler with hardware tablewalk support
From: Scott Wood @ 2014-01-09  1:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Mihai Caraman
In-Reply-To: <1389231163-11175-1-git-send-email-scottwood@freescale.com>

There are a few things that make the existing hw tablewalk handlers
unsuitable for e6500:

 - Indirect entries go in TLB1 (though the resulting direct entries go in
   TLB0).

 - It has threads, but no "tlbsrx." -- so we need a spinlock and
   a normal "tlbsx".  Because we need this lock, hardware tablewalk
   is mandatory on e6500 unless we want to add spinlock+tlbsx to
   the normal bolted TLB miss handler.

 - TLB1 has no HES (nor next-victim hint) so we need software round robin
   (TODO: integrate this round robin data with hugetlb/KVM)

 - The existing tablewalk handlers map half of a page table at a time,
   because IBM hardware has a fixed 1MiB indirect page size.  e6500
   has variable size indirect entries, with a minimum of 2MiB.
   So we can't do the half-page indirect mapping, and even if we
   could it would be less efficient than mapping the full page.

 - Like on e5500, the linear mapping is bolted, so we don't need the
   overhead of supporting nested tlb misses.

Note that hardware tablewalk does not work in rev1 of e6500.
We do not expect to support e6500 rev1 in mainline Linux.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Cc: Mihai Caraman <mihai.caraman@freescale.com>
---
v4: Ensure that MAS2 is 2M-aligned when writing an indirect entry.
It doesn't matter on real e6500 hardware, but it was noticed when
running under KVM, and the architecture does say that those bits
"software should set these bits to zero".

 arch/powerpc/include/asm/mmu-book3e.h |  13 +++
 arch/powerpc/include/asm/mmu.h        |  21 +++--
 arch/powerpc/include/asm/paca.h       |   6 ++
 arch/powerpc/kernel/asm-offsets.c     |   9 ++
 arch/powerpc/kernel/paca.c            |   5 +
 arch/powerpc/kernel/setup_64.c        |  31 ++++++
 arch/powerpc/mm/fsl_booke_mmu.c       |   7 ++
 arch/powerpc/mm/mem.c                 |   6 ++
 arch/powerpc/mm/tlb_low_64e.S         | 171 ++++++++++++++++++++++++++++++++++
 arch/powerpc/mm/tlb_nohash.c          |  93 ++++++++++++------
 10 files changed, 326 insertions(+), 36 deletions(-)

diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 936db36..89b785d 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -286,8 +286,21 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize)
 extern int mmu_linear_psize;
 extern int mmu_vmemmap_psize;
 
+struct tlb_core_data {
+	/* For software way selection, as on Freescale TLB1 */
+	u8 esel_next, esel_max, esel_first;
+
+	/* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */
+	u8 lock;
+};
+
 #ifdef CONFIG_PPC64
 extern unsigned long linear_map_top;
+extern int book3e_htw_mode;
+
+#define PPC_HTW_NONE	0
+#define PPC_HTW_IBM	1
+#define PPC_HTW_E6500	2
 
 /*
  * 64-bit booke platforms don't load the tlb in the tlb miss handler code.
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 691fd8a..f8d1d6d 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -180,16 +180,17 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
 #define MMU_PAGE_64K_AP	3	/* "Admixed pages" (hash64 only) */
 #define MMU_PAGE_256K	4
 #define MMU_PAGE_1M	5
-#define MMU_PAGE_4M	6
-#define MMU_PAGE_8M	7
-#define MMU_PAGE_16M	8
-#define MMU_PAGE_64M	9
-#define MMU_PAGE_256M	10
-#define MMU_PAGE_1G	11
-#define MMU_PAGE_16G	12
-#define MMU_PAGE_64G	13
-
-#define MMU_PAGE_COUNT	14
+#define MMU_PAGE_2M	6
+#define MMU_PAGE_4M	7
+#define MMU_PAGE_8M	8
+#define MMU_PAGE_16M	9
+#define MMU_PAGE_64M	10
+#define MMU_PAGE_256M	11
+#define MMU_PAGE_1G	12
+#define MMU_PAGE_16G	13
+#define MMU_PAGE_64G	14
+
+#define MMU_PAGE_COUNT	15
 
 #if defined(CONFIG_PPC_STD_MMU_64)
 /* 64-bit classic hash table MMU */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index c3523d1..e81731c 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -113,6 +113,10 @@ struct paca_struct {
 	/* Keep pgd in the same cacheline as the start of extlb */
 	pgd_t *pgd __attribute__((aligned(0x80))); /* Current PGD */
 	pgd_t *kernel_pgd;		/* Kernel PGD */
+
+	/* Shared by all threads of a core -- points to tcd of first thread */
+	struct tlb_core_data *tcd_ptr;
+
 	/* We can have up to 3 levels of reentrancy in the TLB miss handler */
 	u64 extlb[3][EX_TLB_SIZE / sizeof(u64)];
 	u64 exmc[8];		/* used for machine checks */
@@ -123,6 +127,8 @@ struct paca_struct {
 	void *mc_kstack;
 	void *crit_kstack;
 	void *dbg_kstack;
+
+	struct tlb_core_data tcd;
 #endif /* CONFIG_PPC_BOOK3E */
 
 	mm_context_t context;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 41a2839..ed8d68c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -203,6 +203,15 @@ int main(void)
 	DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack));
 	DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack));
 	DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack));
+	DEFINE(PACA_TCD_PTR, offsetof(struct paca_struct, tcd_ptr));
+
+	DEFINE(TCD_ESEL_NEXT,
+		offsetof(struct tlb_core_data, esel_next));
+	DEFINE(TCD_ESEL_MAX,
+		offsetof(struct tlb_core_data, esel_max));
+	DEFINE(TCD_ESEL_FIRST,
+		offsetof(struct tlb_core_data, esel_first));
+	DEFINE(TCD_LOCK, offsetof(struct tlb_core_data, lock));
 #endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef CONFIG_PPC_STD_MMU_64
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 623c356..bf0aada 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -160,6 +160,11 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
 #ifdef CONFIG_PPC_STD_MMU_64
 	new_paca->slb_shadow_ptr = init_slb_shadow(cpu);
 #endif /* CONFIG_PPC_STD_MMU_64 */
+
+#ifdef CONFIG_PPC_BOOK3E
+	/* For now -- if we have threads this will be adjusted later */
+	new_paca->tcd_ptr = &new_paca->tcd;
+#endif
 }
 
 /* Put the paca pointer into r13 and SPRG_PACA */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 2232aff..1ce9b87 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -97,6 +97,36 @@ int dcache_bsize;
 int icache_bsize;
 int ucache_bsize;
 
+#if defined(CONFIG_PPC_BOOK3E) && defined(CONFIG_SMP)
+static void setup_tlb_core_data(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		int first = cpu_first_thread_sibling(cpu);
+
+		paca[cpu].tcd_ptr = &paca[first].tcd;
+
+		/*
+		 * If we have threads, we need either tlbsrx.
+		 * or e6500 tablewalk mode, or else TLB handlers
+		 * will be racy and could produce duplicate entries.
+		 */
+		if (smt_enabled_at_boot >= 2 &&
+		    !mmu_has_feature(MMU_FTR_USE_TLBRSRV) &&
+		    book3e_htw_mode != PPC_HTW_E6500) {
+			/* Should we panic instead? */
+			WARN_ONCE("%s: unsupported MMU configuration -- expect problems\n",
+				  __func__);
+		}
+	}
+}
+#else
+static void setup_tlb_core_data(void)
+{
+}
+#endif
+
 #ifdef CONFIG_SMP
 
 static char *smt_enabled_cmdline;
@@ -445,6 +475,7 @@ void __init setup_system(void)
 
 	smp_setup_cpu_maps();
 	check_smt_enabled();
+	setup_tlb_core_data();
 
 #ifdef CONFIG_SMP
 	/* Release secondary cpus out of their spinloops at 0x60 now that
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index a68671c..94cd728 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -52,6 +52,7 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 #include <asm/setup.h>
+#include <asm/paca.h>
 
 #include "mmu_decl.h"
 
@@ -191,6 +192,12 @@ static unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt,
 	}
 	tlbcam_index = i;
 
+#ifdef CONFIG_PPC64
+	get_paca()->tcd.esel_next = i;
+	get_paca()->tcd.esel_max = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+	get_paca()->tcd.esel_first = i;
+#endif
+
 	return amount_mapped;
 }
 
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 3fa93dc..94448cd 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -307,6 +307,12 @@ static void __init register_page_bootmem_info(void)
 
 void __init mem_init(void)
 {
+	/*
+	 * book3s is limited to 16 page sizes due to encoding this in
+	 * a 4-bit field for slices.
+	 */
+	BUILD_BUG_ON(MMU_PAGE_COUNT > 16);
+
 #ifdef CONFIG_SWIOTLB
 	swiotlb_init(0);
 #endif
diff --git a/arch/powerpc/mm/tlb_low_64e.S b/arch/powerpc/mm/tlb_low_64e.S
index b4113bf..75f5d27 100644
--- a/arch/powerpc/mm/tlb_low_64e.S
+++ b/arch/powerpc/mm/tlb_low_64e.S
@@ -239,6 +239,177 @@ itlb_miss_fault_bolted:
 	beq	tlb_miss_common_bolted
 	b	itlb_miss_kernel_bolted
 
+/*
+ * TLB miss handling for e6500 and derivatives, using hardware tablewalk.
+ *
+ * Linear mapping is bolted: no virtual page table or nested TLB misses
+ * Indirect entries in TLB1, hardware loads resulting direct entries
+ *    into TLB0
+ * No HES or NV hint on TLB1, so we need to do software round-robin
+ * No tlbsrx. so we need a spinlock, and we have to deal
+ *    with MAS-damage caused by tlbsx
+ * 4K pages only
+ */
+
+	START_EXCEPTION(instruction_tlb_miss_e6500)
+	tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0
+
+	ld	r11,PACA_TCD_PTR(r13)
+	srdi.	r15,r16,60		/* get region */
+	ori	r16,r16,1
+
+	TLB_MISS_STATS_SAVE_INFO_BOLTED
+	bne	tlb_miss_kernel_e6500	/* user/kernel test */
+
+	b	tlb_miss_common_e6500
+
+	START_EXCEPTION(data_tlb_miss_e6500)
+	tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR
+
+	ld	r11,PACA_TCD_PTR(r13)
+	srdi.	r15,r16,60		/* get region */
+	rldicr	r16,r16,0,62
+
+	TLB_MISS_STATS_SAVE_INFO_BOLTED
+	bne	tlb_miss_kernel_e6500	/* user vs kernel check */
+
+/*
+ * This is the guts of the TLB miss handler for e6500 and derivatives.
+ * We are entered with:
+ *
+ * r16 = page of faulting address (low bit 0 if data, 1 if instruction)
+ * r15 = crap (free to use)
+ * r14 = page table base
+ * r13 = PACA
+ * r11 = tlb_per_core ptr
+ * r10 = crap (free to use)
+ */
+tlb_miss_common_e6500:
+	/*
+	 * Search if we already have an indirect entry for that virtual
+	 * address, and if we do, bail out.
+	 *
+	 * MAS6:IND should be already set based on MAS4
+	 */
+	addi	r10,r11,TCD_LOCK
+1:	lbarx	r15,0,r10
+	cmpdi	r15,0
+	bne	2f
+	li	r15,1
+	stbcx.	r15,0,r10
+	bne	1b
+	.subsection 1
+2:	lbz	r15,0(r10)
+	cmpdi	r15,0
+	bne	2b
+	b	1b
+	.previous
+
+	mfspr	r15,SPRN_MAS2
+
+	tlbsx	0,r16
+	mfspr	r10,SPRN_MAS1
+	andis.	r10,r10,MAS1_VALID@h
+	bne	tlb_miss_done_e6500
+
+	/* Undo MAS-damage from the tlbsx */
+	mfspr	r10,SPRN_MAS1
+	oris	r10,r10,MAS1_VALID@h
+	mtspr	SPRN_MAS1,r10
+	mtspr	SPRN_MAS2,r15
+
+	/* Now, we need to walk the page tables. First check if we are in
+	 * range.
+	 */
+	rldicl.	r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
+	bne-	tlb_miss_fault_e6500
+
+	rldicl	r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3
+	cmpldi	cr0,r14,0
+	clrrdi	r15,r15,3
+	beq-	tlb_miss_fault_e6500 /* No PGDIR, bail */
+	ldx	r14,r14,r15		/* grab pgd entry */
+
+	rldicl	r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
+	clrrdi	r15,r15,3
+	cmpdi	cr0,r14,0
+	bge	tlb_miss_fault_e6500	/* Bad pgd entry or hugepage; bail */
+	ldx	r14,r14,r15		/* grab pud entry */
+
+	rldicl	r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3
+	clrrdi	r15,r15,3
+	cmpdi	cr0,r14,0
+	bge	tlb_miss_fault_e6500
+	ldx	r14,r14,r15		/* Grab pmd entry */
+
+	mfspr	r10,SPRN_MAS0
+	cmpdi	cr0,r14,0
+	bge	tlb_miss_fault_e6500
+
+	/* Now we build the MAS for a 2M indirect page:
+	 *
+	 * MAS 0   :	ESEL needs to be filled by software round-robin
+	 * MAS 1   :	Fully set up
+	 *               - PID already updated by caller if necessary
+	 *               - TSIZE for now is base ind page size always
+	 *               - TID already cleared if necessary
+	 * MAS 2   :	Default not 2M-aligned, need to be redone
+	 * MAS 3+7 :	Needs to be done
+	 */
+
+	ori	r14,r14,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
+	mtspr	SPRN_MAS7_MAS3,r14
+
+	clrrdi	r15,r16,21		/* make EA 2M-aligned */
+	mtspr	SPRN_MAS2,r15
+
+	lbz	r15,TCD_ESEL_NEXT(r11)
+	lbz	r16,TCD_ESEL_MAX(r11)
+	lbz	r14,TCD_ESEL_FIRST(r11)
+	rlwimi	r10,r15,16,0x00ff0000	/* insert esel_next into MAS0 */
+	addi	r15,r15,1		/* increment esel_next */
+	mtspr	SPRN_MAS0,r10
+	cmpw	r15,r16
+	iseleq	r15,r14,r15		/* if next == last use first */
+	stb	r15,TCD_ESEL_NEXT(r11)
+
+	tlbwe
+
+tlb_miss_done_e6500:
+	.macro	tlb_unlock_e6500
+	li	r15,0
+	isync
+	stb	r15,TCD_LOCK(r11)
+	.endm
+
+	tlb_unlock_e6500
+	TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK)
+	tlb_epilog_bolted
+	rfi
+
+tlb_miss_kernel_e6500:
+	mfspr	r10,SPRN_MAS1
+	ld	r14,PACA_KERNELPGD(r13)
+	cmpldi	cr0,r15,8		/* Check for vmalloc region */
+	rlwinm	r10,r10,0,16,1		/* Clear TID */
+	mtspr	SPRN_MAS1,r10
+	beq+	tlb_miss_common_e6500
+
+tlb_miss_fault_e6500:
+	tlb_unlock_e6500
+	/* We need to check if it was an instruction miss */
+	andi.	r16,r16,1
+	bne	itlb_miss_fault_e6500
+dtlb_miss_fault_e6500:
+	TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+	tlb_epilog_bolted
+	b	exc_data_storage_book3e
+itlb_miss_fault_e6500:
+	TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+	tlb_epilog_bolted
+	b	exc_instruction_storage_book3e
+
+
 /**********************************************************************
  *                                                                    *
  * TLB miss handling for Book3E with TLB reservation and HES support  *
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index 8805b7b..735839b 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -43,6 +43,7 @@
 #include <asm/tlb.h>
 #include <asm/code-patching.h>
 #include <asm/hugetlb.h>
+#include <asm/paca.h>
 
 #include "mmu_decl.h"
 
@@ -58,6 +59,10 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
 		.shift	= 12,
 		.enc	= BOOK3E_PAGESZ_4K,
 	},
+	[MMU_PAGE_2M] = {
+		.shift	= 21,
+		.enc	= BOOK3E_PAGESZ_2M,
+	},
 	[MMU_PAGE_4M] = {
 		.shift	= 22,
 		.enc	= BOOK3E_PAGESZ_4M,
@@ -136,7 +141,7 @@ static inline int mmu_get_tsize(int psize)
 int mmu_linear_psize;		/* Page size used for the linear mapping */
 int mmu_pte_psize;		/* Page size used for PTE pages */
 int mmu_vmemmap_psize;		/* Page size used for the virtual mem map */
-int book3e_htw_enabled;		/* Is HW tablewalk enabled ? */
+int book3e_htw_mode;		/* HW tablewalk?  Value is PPC_HTW_* */
 unsigned long linear_map_top;	/* Top of linear mapping */
 
 #endif /* CONFIG_PPC64 */
@@ -377,7 +382,7 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
 {
 	int tsize = mmu_psize_defs[mmu_pte_psize].enc;
 
-	if (book3e_htw_enabled) {
+	if (book3e_htw_mode != PPC_HTW_NONE) {
 		unsigned long start = address & PMD_MASK;
 		unsigned long end = address + PMD_SIZE;
 		unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
@@ -430,7 +435,7 @@ static void setup_page_sizes(void)
 			def = &mmu_psize_defs[psize];
 			shift = def->shift;
 
-			if (shift == 0)
+			if (shift == 0 || shift & 1)
 				continue;
 
 			/* adjust to be in terms of 4^shift Kb */
@@ -440,21 +445,40 @@ static void setup_page_sizes(void)
 				def->flags |= MMU_PAGE_SIZE_DIRECT;
 		}
 
-		goto no_indirect;
+		goto out;
 	}
 
 	if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
-		u32 tlb1ps = mfspr(SPRN_TLB1PS);
+		u32 tlb1cfg, tlb1ps;
+
+		tlb0cfg = mfspr(SPRN_TLB0CFG);
+		tlb1cfg = mfspr(SPRN_TLB1CFG);
+		tlb1ps = mfspr(SPRN_TLB1PS);
+		eptcfg = mfspr(SPRN_EPTCFG);
+
+		if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT))
+			book3e_htw_mode = PPC_HTW_E6500;
+
+		/*
+		 * We expect 4K subpage size and unrestricted indirect size.
+		 * The lack of a restriction on indirect size is a Freescale
+		 * extension, indicated by PSn = 0 but SPSn != 0.
+		 */
+		if (eptcfg != 2)
+			book3e_htw_mode = PPC_HTW_NONE;
 
 		for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
 			struct mmu_psize_def *def = &mmu_psize_defs[psize];
 
 			if (tlb1ps & (1U << (def->shift - 10))) {
 				def->flags |= MMU_PAGE_SIZE_DIRECT;
+
+				if (book3e_htw_mode && psize == MMU_PAGE_2M)
+					def->flags |= MMU_PAGE_SIZE_INDIRECT;
 			}
 		}
 
-		goto no_indirect;
+		goto out;
 	}
 #endif
 
@@ -471,8 +495,11 @@ static void setup_page_sizes(void)
 	}
 
 	/* Indirect page sizes supported ? */
-	if ((tlb0cfg & TLBnCFG_IND) == 0)
-		goto no_indirect;
+	if ((tlb0cfg & TLBnCFG_IND) == 0 ||
+	    (tlb0cfg & TLBnCFG_PT) == 0)
+		goto out;
+
+	book3e_htw_mode = PPC_HTW_IBM;
 
 	/* Now, we only deal with one IND page size for each
 	 * direct size. Hopefully all implementations today are
@@ -497,8 +524,8 @@ static void setup_page_sizes(void)
 				def->ind = ps + 10;
 		}
 	}
- no_indirect:
 
+out:
 	/* Cleanup array and print summary */
 	pr_info("MMU: Supported page sizes\n");
 	for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
@@ -520,23 +547,23 @@ static void setup_page_sizes(void)
 
 static void setup_mmu_htw(void)
 {
-	/* Check if HW tablewalk is present, and if yes, enable it by:
-	 *
-	 * - patching the TLB miss handlers to branch to the
-	 *   one dedicates to it
-	 *
-	 * - setting the global book3e_htw_enabled
-       	 */
-	unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+	/*
+	 * If we want to use HW tablewalk, enable it by patching the TLB miss
+	 * handlers to branch to the one dedicated to it.
+	 */
 
-	if ((tlb0cfg & TLBnCFG_IND) &&
-	    (tlb0cfg & TLBnCFG_PT)) {
+	switch (book3e_htw_mode) {
+	case PPC_HTW_IBM:
 		patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e);
 		patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e);
-		book3e_htw_enabled = 1;
+		break;
+	case PPC_HTW_E6500:
+		patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
+		patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
+		break;
 	}
 	pr_info("MMU: Book3E HW tablewalk %s\n",
-		book3e_htw_enabled ? "enabled" : "not supported");
+		book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported");
 }
 
 /*
@@ -576,8 +603,16 @@ static void __early_init_mmu(int boot_cpu)
 	/* Set MAS4 based on page table setting */
 
 	mas4 = 0x4 << MAS4_WIMGED_SHIFT;
-	if (book3e_htw_enabled) {
-		mas4 |= mas4 | MAS4_INDD;
+	switch (book3e_htw_mode) {
+	case PPC_HTW_E6500:
+		mas4 |= MAS4_INDD;
+		mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT;
+		mas4 |= MAS4_TLBSELD(1);
+		mmu_pte_psize = MMU_PAGE_2M;
+		break;
+
+	case PPC_HTW_IBM:
+		mas4 |= MAS4_INDD;
 #ifdef CONFIG_PPC_64K_PAGES
 		mas4 |=	BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT;
 		mmu_pte_psize = MMU_PAGE_256M;
@@ -585,13 +620,16 @@ static void __early_init_mmu(int boot_cpu)
 		mas4 |=	BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
 		mmu_pte_psize = MMU_PAGE_1M;
 #endif
-	} else {
+		break;
+
+	case PPC_HTW_NONE:
 #ifdef CONFIG_PPC_64K_PAGES
 		mas4 |=	BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT;
 #else
 		mas4 |=	BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
 #endif
 		mmu_pte_psize = mmu_virtual_psize;
+		break;
 	}
 	mtspr(SPRN_MAS4, mas4);
 
@@ -611,8 +649,11 @@ static void __early_init_mmu(int boot_cpu)
 		/* limit memory so we dont have linear faults */
 		memblock_enforce_memory_limit(linear_map_top);
 
-		patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
-		patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e);
+		if (book3e_htw_mode == PPC_HTW_NONE) {
+			patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
+			patch_exception(0x1e0,
+				exc_instruction_tlb_miss_bolted_book3e);
+		}
 	}
 #endif
 
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH v4 3/3] powerpc/fsl-book3e-64: Use paca for hugetlb TLB1 entry selection
From: Scott Wood @ 2014-01-09  1:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood
In-Reply-To: <1389231163-11175-1-git-send-email-scottwood@freescale.com>

This keeps usage coordinated for hugetlb and indirect entries, which
should make entry selection more predictable and probably improve overall
performance when mixing the two.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
v4: no change

 arch/powerpc/mm/hugetlbpage-book3e.c | 51 +++++++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/mm/hugetlbpage-book3e.c b/arch/powerpc/mm/hugetlbpage-book3e.c
index 646c4bf..5e4ee25 100644
--- a/arch/powerpc/mm/hugetlbpage-book3e.c
+++ b/arch/powerpc/mm/hugetlbpage-book3e.c
@@ -8,6 +8,44 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#ifdef CONFIG_PPC64
+static inline int tlb1_next(void)
+{
+	struct paca_struct *paca = get_paca();
+	struct tlb_core_data *tcd;
+	int this, next;
+
+	tcd = paca->tcd_ptr;
+	this = tcd->esel_next;
+
+	next = this + 1;
+	if (next >= tcd->esel_max)
+		next = tcd->esel_first;
+
+	tcd->esel_next = next;
+	return this;
+}
+#else
+static inline int tlb1_next(void)
+{
+	int index, ncams;
+
+	ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+
+	index = __get_cpu_var(next_tlbcam_idx);
+
+	/* Just round-robin the entries and wrap when we hit the end */
+	if (unlikely(index == ncams - 1))
+		__get_cpu_var(next_tlbcam_idx) = tlbcam_index;
+	else
+		__get_cpu_var(next_tlbcam_idx)++;
+
+	return index;
+}
+#endif /* !PPC64 */
+#endif /* FSL */
+
 static inline int mmu_get_tsize(int psize)
 {
 	return mmu_psize_defs[psize].enc;
@@ -47,7 +85,7 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
 	struct mm_struct *mm;
 
 #ifdef CONFIG_PPC_FSL_BOOK3E
-	int index, ncams;
+	int index;
 #endif
 
 	if (unlikely(is_kernel_addr(ea)))
@@ -77,18 +115,11 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
 	}
 
 #ifdef CONFIG_PPC_FSL_BOOK3E
-	ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
-
 	/* We have to use the CAM(TLB1) on FSL parts for hugepages */
-	index = __get_cpu_var(next_tlbcam_idx);
+	index = tlb1_next();
 	mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1));
-
-	/* Just round-robin the entries and wrap when we hit the end */
-	if (unlikely(index == ncams - 1))
-		__get_cpu_var(next_tlbcam_idx) = tlbcam_index;
-	else
-		__get_cpu_var(next_tlbcam_idx)++;
 #endif
+
 	mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize);
 	mas2 = ea & ~((1UL << shift) - 1);
 	mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK;
-- 
1.8.3.2

^ permalink raw reply related

* Re: [PATCH] powerpc: Fix alignment of secondary cpu spin vars
From: Benjamin Herrenschmidt @ 2014-01-09  1:36 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Michael Ellerman, linuxppc-dev, linux-kernel@vger.kernel.org,
	Anton Blanchard, chzigotzky
In-Reply-To: <20140108174828.GA16830@quad.lixom.net>

On Wed, 2014-01-08 at 09:48 -0800, Olof Johansson wrote:

> >         /* If it's a display, note it */
> > -       memset(type, 0, sizeof(type));
> > -       prom_getprop(stdout_node, "device_type", type, sizeof(type));
> > -       if (strcmp(type, "display") == 0)
> > -               prom_setprop(stdout_node, path, "linux,boot-display", NULL, 0);
> > +       stdout_node = call_prom("instance-to-package", 1, 1, prom.stdout);
> > +       if (stdout_node != PROM_ERROR) {
> > +               val = cpu_to_be32(stdout_node);
> > +               memset(type, 0, sizeof(type));
> > +               prom_getprop(stdout_node, "device_type", type, sizeof(type));
> > +               if (strcmp(type, "display") == 0)
> > +                       prom_setprop(stdout_node, path, "linux,boot-display", NU
> 
> Line is cut off, this needs "NULL, 0);" at the end.

Right, copy/paste failure :-)

Thanks, I'll try to get that to Linus before he cuts .13, otherwise it
will be -stable.

Cheers,
Ben.

^ permalink raw reply

* Re: [v3, 3/7] powerpc: enable the relocatable support for the fsl booke 32bit kernel
From: Kevin Hao @ 2014-01-09  1:39 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc
In-Reply-To: <20140109000219.GA6884@home.buserror.net>

[-- Attachment #1: Type: text/plain, Size: 1375 bytes --]

On Wed, Jan 08, 2014 at 06:02:19PM -0600, Scott Wood wrote:
> On Wed, Jan 08, 2014 at 10:42:35AM +0800, Kevin Hao wrote:
> > On Tue, Jan 07, 2014 at 05:46:04PM -0600, Scott Wood wrote:
> > > Oh.  I think it'd be more readable to do "offset = start -
> > > memstart_addr" and add offset instead of subtracting it.
> > 
> > Yes, I agree. The reason that I use "offset = memstart_addr - start" is that
> > it seems "memstart_addr" is always greater than "start" when we are booting
> > a kdump kernel with a kernel option like "crashkernel=64M@80M". :-)
> > 
> > > 
> > > Also, offset should be phys_addr_t -- even if you don't expect to
> > > support offsets greater than 4G on 32-bit, it's semantically the right
> > > type to use.  Plus, "int" would break if this code were ever used with
> > > 64-bit.
> > 
> > I thought about using phy_addr_t for the "offset" originally but gave it up
> > for the following reasons:
> >   * It will not be greater than 4G.
> >   * We have to use the ugly #ifdef CONFIG_PHYS_64BIT in restore_to_as0().
> >   * Need more registers for arguments for restore_to_as0().
> > 
> > Of course you can change it to phys_addr_t if you prefer.
> 
> Here's the diff I made when applying (also changed the subf in patch 9 to
> add)

Looks fine to me. I also done a boot test and it works pretty well.
Thanks Scott.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply

* Re: [PATCH 02/12][v4] pci: fsl: add structure fsl_pci
From: Lian Minghuan-b31939 @ 2014-01-09  2:22 UTC (permalink / raw)
  To: Scott Wood, Minghuan Lian
  Cc: Bjorn Helgaas, linux-pci, linuxppc-dev, Zang Roy-R61911
In-Reply-To: <1389218288.25654.26.camel@snotra.buserror.net>

Hi Scott,

please see my comments inline.

On 01/09/2014 05:58 AM, Scott Wood wrote:
> On Wed, 2014-01-08 at 13:01 +0800, Minghuan Lian wrote:
>> PowerPC uses structure pci_controller to describe PCI controller,
>> but ARM uses structure pci_sys_data. In order to support PowerPC
>> and ARM simultaneously, the patch adds a structure fsl_pci that
>> contains most of the members of the pci_controller and pci_sys_data.
>> Meanwhile, it defines a interface fsl_arch_sys_to_pci() which should
>> be implemented in architecture-specific PCI controller driver to
>> convert pci_controller or pci_sys_data to fsl_pci.
>>
>> Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
>> ---
>> change log:
>> v4:
>> Added indirect type macro
>> v1-v3:
>> Derived from http://patchwork.ozlabs.org/patch/278965/
>>
>> Based on upstream master.
>> Based on the discussion of RFC version here
>> http://patchwork.ozlabs.org/patch/274487/
>>
>>   include/linux/fsl/pci-common.h | 48 ++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 48 insertions(+)
> Same comments on this patchset as last time.
[Minghuan] I added the duplicate fields because PPC's struct 
pci_controller need them.
The common PCI driver gets the related information and pass to PowerPC 
driver.
The most fileds are parsed from dts. the common driver need them to 
initialize the ATMU
and access the PCI configuration. If fsl_pci does not contains them, 
PowerPC driver must parse
parse dts or access controller to get the information again. The best 
way is PowerPC and ARM can use
the common pci_controller structure, but currently, it is very hard and 
needs more effort. So I create fsl_pci
that contains most of the members of the pci_controller and pci_sys_data.


please see the following code for PowerPC:
int fsl_arch_pci_sys_register(struct fsl_pci *pci)
+{
+    struct pci_controller *hose;

+    hose = pcibios_alloc_controller(pci->dn);
+
+    hose->private_data = pci;
+    hose->parent = pci->dev;
+    hose->first_busno = pci->first_busno;
+    hose->last_busno = pci->last_busno;
+    hose->ops = pci->ops;
+
+    hose->io_base_virt = ioremap(pci->io_base_phys + 
pci->io_resource.start,
+                     pci->pci_io_size);
+    hose->pci_io_size = pci->io_resource.start + pci->pci_io_size;
+    hose->io_base_phys = pci->io_base_phys;
+    hose->io_resource = pci->io_resource;
+
+    memcpy(hose->mem_offset, pci->mem_offset, sizeof(hose->mem_offset));
+    memcpy(hose->mem_resources, pci->mem_resources,
+        sizeof(hose->mem_resources));
+    hose->dma_window_base_cur = pci->dma_window_base_cur;
+    hose->dma_window_size = pci->dma_window_size;
+    pci->sys = hose;
+....
+    return 0;
+}



The following is for ARM, I will submit them after verification:

+
+static inline struct fsl_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+    return sys->private_data;
+}
+
+static int fsl_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+    struct fsl_pcie *pcie;
+
+    pcie = sys_to_pcie(sys);
+
+    if (!pcie)
+        return 0;
+
+    pcie->sys = sys;
+
+    sys->io_offset = pcie->io_base_phys;
+    pci_ioremap_io(sys->io_offset, pcie->io_resource.start);
+    pci_add_resource_offset(&sys->resources, &pcie->io_resource,
+                sys->io_offset);
+
+    sys->mem_offset = pcie->mem_offset;
+    pci_add_resource_offset(&sys->resources, &pcie->mem_resource,
+                sys->mem_offset);
+
+    return 1;
+}
+
+static struct pci_bus *
+fsl_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+    struct pci_bus *bus;
+    struct fsl_pcie *pcie = sys_to_pcie(sys);
+
+    bus = pci_create_root_bus(pcie->dev, sys->busnr,
+                  pcie->ops, sys, &sys->resources);
+    if (!bus)
+        return NULL;
+
+    pci_scan_child_bus(bus);
+
+    return bus;
+}
+
+static int fsl_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 hw_pci fsl_hw_pcie = {
+    .ops        = &fsl_indirect_pci_ops;
+    .setup        = fsl_pcie_setup,
+    .scan        = fsl_pcie_scan_bus,
+    .map_irq    = fsl_pcie_map_irq,
+};

+static struct pci_bus *
+fake_pci_bus(struct fsl_pcie *pcie, int busnr)
+{
+    static struct pci_bus bus;
+    static struct pci_sys_data sys;
+
+    bus.number = busnr;
+    bus.sysdata = &sys;
+    sys.private_data = pcie;
+    bus.ops = pcie->ops;
+    return &bus;
+}
+
+static int fsl_pcie_register(struct fsl_pcie *pcie)
+{
+    pcie->controller = fsl_hw_pcie.nr_controllers;
+    fsl_hw_pcie.nr_controllers = 1;
+    fsl_hw_pcie.private_data = (void **)&pcie;
+
+    pci_common_init(&fsl_hw_pcie);
+    pci_assign_unassigned_resources();
+#ifdef CONFIG_PCI_DOMAINS
+    fsl_hw_pcie.domain++;
+#endif
+}
>
> -Scott
>
>

^ permalink raw reply

* RE: 答复: [v7] clk: corenet: Adds the clock binding
From: Yuantian Tang @ 2014-01-09  2:57 UTC (permalink / raw)
  To: Scott Wood, Mark Rutland
  Cc: devicetree@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1389206619.25654.9.camel@snotra.buserror.net>

VGhhbmtzIGZvciB5b3UgcmV2aWV3Lg0KU2VlIG15IHJlc3BvbnNlIGlubGluZS4NCg0KVGhhbmtz
LA0KWXVhbnRpYW4NCg0KPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiBXb29k
IFNjb3R0LUIwNzQyMQ0KPiBTZW50OiAyMDE05bm0MeaciDnml6Ug5pif5pyf5ZubIDI6NDQNCj4g
VG86IE1hcmsgUnV0bGFuZA0KPiBDYzogVGFuZyBZdWFudGlhbi1CMjk5ODM7IGdhbGFrQGtlcm5l
bC5jcmFzaGluZy5vcmc7DQo+IGRldmljZXRyZWVAdmdlci5rZXJuZWwub3JnOyBsaW51eHBwYy1k
ZXZAbGlzdHMub3psYWJzLm9yZw0KPiBTdWJqZWN0OiBSZTog562U5aSNOiBbdjddIGNsazogY29y
ZW5ldDogQWRkcyB0aGUgY2xvY2sgYmluZGluZw0KPiANCj4gT24gV2VkLCAyMDE0LTAxLTA4IGF0
IDA5OjMwICswMDAwLCBNYXJrIFJ1dGxhbmQgd3JvdGU6DQo+ID4gT24gV2VkLCBKYW4gMDgsIDIw
MTQgYXQgMDg6NTM6NTZBTSArMDAwMCwgWXVhbnRpYW4gVGFuZyB3cm90ZToNCj4gPiA+DQo+ID4g
PiBfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQo+ID4gPiDlj5Hku7bk
uro6IFdvb2QgU2NvdHQtQjA3NDIxDQo+ID4gPiDlj5HpgIHml7bpl7Q6IDIwMTTlubQx5pyIOOaX
pSA4OjIxDQo+ID4gPiDmlLbku7bkuro6IFRhbmcgWXVhbnRpYW4tQjI5OTgzDQo+ID4gPiDmioTp
gIE6IGdhbGFrQGtlcm5lbC5jcmFzaGluZy5vcmc7IG1hcmsucnV0bGFuZEBhcm0uY29tOw0KPiA+
ID4gZGV2aWNldHJlZUB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMu
b3JnDQo+ID4gPiDkuLvpopg6IFJlOiBbdjddIGNsazogY29yZW5ldDogQWRkcyB0aGUgY2xvY2sg
YmluZGluZw0KPiA+ID4NCj4gPiA+IE9uIFdlZCwgTm92IDIwLCAyMDEzIGF0IDA1OjA0OjQ5UE0g
KzA4MDAsIHRhbmcgeXVhbnRpYW4gd3JvdGU6DQo+ID4gPiA+ICtSZWNvbW1lbmRlZCBwcm9wZXJ0
aWVzOg0KPiA+ID4gPiArLSByYW5nZXM6IEFsbG93cyB2YWxpZCB0cmFuc2xhdGlvbiBiZXR3ZWVu
IGNoaWxkJ3MgYWRkcmVzcyBzcGFjZQ0KPiBhbmQNCj4gPiA+ID4gKyAgICAgcGFyZW50J3MuIE11
c3QgYmUgcHJlc2VudCBpZiB0aGUgZGV2aWNlIGhhcyBzdWItbm9kZXMuDQo+ID4gPiA+ICstICNh
ZGRyZXNzLWNlbGxzOiBTcGVjaWZpZXMgdGhlIG51bWJlciBvZiBjZWxscyB1c2VkIHRvIHJlcHJl
c2VudA0KPiA+ID4gPiArICAgICBwaHlzaWNhbCBiYXNlIGFkZHJlc3Nlcy4gIE11c3QgYmUgcHJl
c2VudCBpZiB0aGUgZGV2aWNlIGhhcw0KPiA+ID4gPiArICAgICBzdWItbm9kZXMgYW5kIHNldCB0
byAxIGlmIHByZXNlbnQNCj4gPiA+ID4gKy0gI3NpemUtY2VsbHM6IFNwZWNpZmllcyB0aGUgbnVt
YmVyIG9mIGNlbGxzIHVzZWQgdG8gcmVwcmVzZW50DQo+ID4gPiA+ICsgICAgIHRoZSBzaXplIG9m
IGFuIGFkZHJlc3MuIE11c3QgYmUgcHJlc2VudCBpZiB0aGUgZGV2aWNlIGhhcw0KPiA+ID4gPiAr
ICAgICBzdWItbm9kZXMgYW5kIHNldCB0byAxIGlmIHByZXNlbnQNCj4gPiA+DQo+ID4gPiBXaHkg
YXJlIHdlIHNwZWNpZnlpbmcgI2FkZHJlc3MtY2VsbHMvI3NpemUtY2VsbHMgaGVyZT8NCj4gPiA+
DQo+ID4gPiBBOiBpdCBoYXMgc3ViLW5vZGVzIHdoaWNoIGhhdmUgUkVHIHByb3BlcnR5LCBkb24n
dCB3ZSBuZWVkIHRvDQo+ID4gPiBzcGVjaWZ5ICNhZGRyZXNzLWNlbGxzLyNzaXplLWNlbGxzPw0K
PiA+DQo+ID4gSWYgYSBub2RlIGhhcyBhIHJlZyBlbnRyeSwgaXRzIHBhcmVudCBzaG91bGQgaGF2
ZSAjc2l6ZS1jZWxscyBhbmQNCj4gPiAjYWRkcmVzcy1jZWxscyB0byBhbGxvdyBpdCB0byBiZSBw
YXJzZWQgcHJvcGVybHkuDQo+IA0KPiBZZXMsIGJ1dCB3aHkgZG8gd2UgbmVlZCB0byBzcGVjaWZ5
IGluIHRoaXMgYmluZGluZyBob3cgbWFueSBjZWxscyB0aGVyZQ0KPiB3aWxsIGJlLCBlc3BlY2lh
bGx5IHNpbmNlIHRoaXMgYmluZGluZyBvbmx5IGFkZHJlc3NlcyB0aGUgY2xvY2sgcHJvdmlkZXIN
Cj4gYXNwZWN0IG9mIHRoZSBjbG9ja2dlbiBub2RlcyAoZS5nLiBpdCBkb2Vzbid0IGRlc2NyaWJl
IHRoZSByZWcpPyAgT3INCj4gcmF0aGVyLCBpdCdzIHBhcnRpYWxseSBkZXNjcmliaW5nIHRoZSBu
b24tY2xvY2sgYXNwZWN0LCBhbmQgZG9lc24ndA0KPiBhZGRyZXNzIHRoZSBjbG9jayBhc3BlY3Qg
YXQgYWxsIEFGQUlDVC4NCj4gDQpGaXJzdCBvZiBhbGwsIHRoZXkgYXJlIG5vdCAiUmVxdWlyZWQg
cHJvcGVydGllcyIsIHRoZXkgYXJlIG9wdGlvbmFsLg0KSWYgcHJlc2VudCwgd2Ugc2hvdWxkIGdp
dmUgdGhlbSBhIHZhbHVlIG9mIDEuDQpUaGVuLCB5ZXMsIHRoaXMgYmluZGluZyBkZXNjcmliZXMg
Y2xvY2tnZW4gbm9kZSB3aGljaCBpcyAiQ0xPQ0sgQkxPQ0siLg0KSXQgc2hvdWxkIHRha2UgY2Fy
ZSBvZiBpdHMgc3ViLW5vZGVzIHdoaWNoIGFyZSBjbG9jayBub2RlcyB0byBiZSBwYXJzZWQgcHJv
cGVybHkuDQoNCj4gV2hlcmUgZG9lcyB0aGUgYWN0dWFsIGlucHV0IGNsb2NrIGZyZXF1ZW5jeSBn
bz8gIFUtQm9vdCBwdXRzIGl0IGluIHRoZQ0KPiBjbG9ja2dlbiBub2RlIGl0c2VsZiBhcyBjbG9j
ay1mcmVxdWVuY3ksIGJ1dCB0aGF0IGlzbid0IGRlc2NyaWJlZCBpbiB0aGUNCj4gYmluZGluZy4g
IEhvdyBkb2VzIHRoYXQgcmVsYXRlIHRvIHRoZSBzeXNjbGsgbm9kZT8gIElmICJmc2wscW9yaXEt
c3lzY2xrLQ0KPiAxLjAiIGlzIHN1cHBvc2VkIHRvIGluZGljYXRlIHRoYXQgY2xvY2stZnJlcXVl
bmN5IGNhbiBiZSBmb3VuZCBpbiB0aGUNCj4gcGFyZW50IG5vZGUsIHRoYXQgaXNuJ3Qgc3BlY2lm
aWVkIGJ5IHRoZSBiaW5kaW5nLCBub3IgaXMgY2xvY2stZnJlcXVlbmN5DQo+IHNob3duIGluIHRo
ZSBleGFtcGxlLg0KPiANCmNsb2NrLWZyZXF1ZW5jeSBpcyBhIHdpcmVkIHByb3BlcnR5LiBJdCBp
cyBpbiBjbG9ja2dlbiBub2RlIHJpZ2h0IG5vdy4NCkJ1dCBpdCBzaG91bGQgYmUgcGxhY2VkIHNv
bWV3aGVyZSBpbiBjbG9jayBub2Rlcy4NCklmIEkgZGVzY3JpYmUgaGVyZSwgSSB3b3VsZCBiZSBh
c2tlZCB3aHkgaXQgaXMgcmVsYXRlZCB0byBjbG9ja2dlbiBub2RlPw0KSWYgeW91IHRoaW5rIHNo
b3dpbmcgaXQgdXAgaXMgT0ssIEkgbGlrZSB0byBkbyBpdC4NCiANCj4gV2hhdCBpcyB0aGUgZGlm
ZmVyZW5jZSBiZXR3ZWVuICJmc2wscW9yaXEtc3lzY2xrLTEuMCIgYW5kICJmc2wscW9yaXEtDQo+
IHN5c2Nsay0yLjAiPyAgSG93IGRvZXMgdGhlIGNvbmNlcHQgb2YgYSBmaXhlZCBpbnB1dCBjbG9j
ayBjaGFuZ2U/DQo+DQpUZWNobmljYWxseSwgdGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBiZXR3ZWVu
ICpzeXNjbGstMS4wIGFuZCAqLTIuMCwganVzdCBsaWtlDQpDbG9ja2dlbi0yLjAgYW5kIDEuMC4g
TmFtaW5nIGxpa2UgdGhpcyBqdXN0IHRvIGluZGljYXRlIHRoZXkgYmVsb25nIHRvIGNoYXNzaXMg
Mi4wIA0KYW5kIDEuMCByZXNwZWN0aXZlbHkuDQoNClJlZ2FyZHMsDQpZdWFudGlhbg0KIA0KPiAt
U2NvdHQNCj4gDQoNCg==

^ permalink raw reply

* [PATCH] pseries/cpuidle: Remove redundant call to ppc64_runlatch_off() in cpu idle routines
From: Preeti U Murthy @ 2014-01-09  5:05 UTC (permalink / raw)
  To: paulus, linuxppc-dev, deepthi, benh

Commit fbd7740fdfdf9475f switched pseries cpu idle handling from complete idle
loops to ppc_md.powersave functions. Earlier to this switch,
ppc64_runlatch_off() had to be called in each of the idle routines. But after
the switch this call is handled in arch_cpu_idle(),just before the call
to ppc_md.powersave, where platform specific idle routines are called.

As a consequence, the call to ppc64_runlatch_off() got duplicated in the
arch_cpu_idle() routine as well as in the some of the idle routines in
pseries and commit fbd7740fdfdf9475f missed to get rid of these redundant
calls. These calls were carried over subsequent enhancements to the pseries
cpuidle routines. This patch takes care of eliminating this redundancy.

Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
---

 arch/powerpc/platforms/pseries/processor_idle.c |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index a166e38..09e4f56 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -17,7 +17,6 @@
 #include <asm/reg.h>
 #include <asm/machdep.h>
 #include <asm/firmware.h>
-#include <asm/runlatch.h>
 #include <asm/plpar_wrappers.h>
 
 struct cpuidle_driver pseries_idle_driver = {
@@ -63,7 +62,6 @@ static int snooze_loop(struct cpuidle_device *dev,
 	set_thread_flag(TIF_POLLING_NRFLAG);
 
 	while ((!need_resched()) && cpu_online(cpu)) {
-		ppc64_runlatch_off();
 		HMT_low();
 		HMT_very_low();
 	}
@@ -103,7 +101,6 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
 	idle_loop_prolog(&in_purr);
 	get_lppaca()->donate_dedicated_cpu = 1;
 
-	ppc64_runlatch_off();
 	HMT_medium();
 	check_and_cede_processor();
 

^ permalink raw reply related

* Re: [PATCH 02/12][v4] pci: fsl: add structure fsl_pci
From: Lian Minghuan-b31939 @ 2014-01-09  5:45 UTC (permalink / raw)
  To: Bjorn Helgaas, Scott Wood
  Cc: linux-pci, Minghuan Lian, linuxppc-dev, Zang Roy-R61911
In-Reply-To: <20140109001252.GA20070@google.com>

Hi Bjorn,

I am very sorry, The  mail was filtered to another directory, I did not 
notice update. The next versions will include these updates.

Thanks,
Minghuan

On 01/09/2014 08:12 AM, Bjorn Helgaas wrote:
> On Wed, Jan 08, 2014 at 03:58:08PM -0600, Scott Wood wrote:
>> On Wed, 2014-01-08 at 13:01 +0800, Minghuan Lian wrote:
>>> PowerPC uses structure pci_controller to describe PCI controller,
>>> but ARM uses structure pci_sys_data. In order to support PowerPC
>>> and ARM simultaneously, the patch adds a structure fsl_pci that
>>> contains most of the members of the pci_controller and pci_sys_data.
>>> Meanwhile, it defines a interface fsl_arch_sys_to_pci() which should
>>> be implemented in architecture-specific PCI controller driver to
>>> convert pci_controller or pci_sys_data to fsl_pci.
>>>
>>> Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
>>> ---
>>> change log:
>>> v4:
>>> Added indirect type macro
>>> v1-v3:
>>> Derived from http://patchwork.ozlabs.org/patch/278965/
>>>
>>> Based on upstream master.
>>> Based on the discussion of RFC version here
>>> http://patchwork.ozlabs.org/patch/274487/
>>>
>>>   include/linux/fsl/pci-common.h | 48 ++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 48 insertions(+)
>> Same comments on this patchset as last time.
> Minghuan, when you address Scott's comments, can you also add a
> MAINTAINERS update?
>
> Bjorn
>
>

^ permalink raw reply

* Re: [PATCH] pseries/cpuidle: Remove redundant call to ppc64_runlatch_off() in cpu idle routines
From: Srivatsa S. Bhat @ 2014-01-09  8:07 UTC (permalink / raw)
  To: Preeti U Murthy; +Cc: linuxppc-dev, paulus, deepthi
In-Reply-To: <20140109050519.11532.6044.stgit@preeti.in.ibm.com>

On 01/09/2014 10:35 AM, Preeti U Murthy wrote:
> Commit fbd7740fdfdf9475f switched pseries cpu idle handling from complete idle
> loops to ppc_md.powersave functions. Earlier to this switch,
> ppc64_runlatch_off() had to be called in each of the idle routines. But after
> the switch this call is handled in arch_cpu_idle(),just before the call
> to ppc_md.powersave, where platform specific idle routines are called.
> 
> As a consequence, the call to ppc64_runlatch_off() got duplicated in the
> arch_cpu_idle() routine as well as in the some of the idle routines in
> pseries and commit fbd7740fdfdf9475f missed to get rid of these redundant
> calls. These calls were carried over subsequent enhancements to the pseries
> cpuidle routines. This patch takes care of eliminating this redundancy.
> 
> Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
> ---

Reviewed-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>

Regards,
Srivatsa S. Bhat

> 
>  arch/powerpc/platforms/pseries/processor_idle.c |    3 ---
>  1 file changed, 3 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
> index a166e38..09e4f56 100644
> --- a/arch/powerpc/platforms/pseries/processor_idle.c
> +++ b/arch/powerpc/platforms/pseries/processor_idle.c
> @@ -17,7 +17,6 @@
>  #include <asm/reg.h>
>  #include <asm/machdep.h>
>  #include <asm/firmware.h>
> -#include <asm/runlatch.h>
>  #include <asm/plpar_wrappers.h>
> 
>  struct cpuidle_driver pseries_idle_driver = {
> @@ -63,7 +62,6 @@ static int snooze_loop(struct cpuidle_device *dev,
>  	set_thread_flag(TIF_POLLING_NRFLAG);
> 
>  	while ((!need_resched()) && cpu_online(cpu)) {
> -		ppc64_runlatch_off();
>  		HMT_low();
>  		HMT_very_low();
>  	}
> @@ -103,7 +101,6 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
>  	idle_loop_prolog(&in_purr);
>  	get_lppaca()->donate_dedicated_cpu = 1;
> 
> -	ppc64_runlatch_off();
>  	HMT_medium();
>  	check_and_cede_processor();
> 
> 

^ permalink raw reply

* [PATCH] powerpc: delete non-required instances of include <linux/init.h>
From: Paul Gortmaker @ 2014-01-09  5:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras; +Cc: Paul Gortmaker, linuxppc-dev

None of these files are actually using any __init type directives
and hence don't need to include <linux/init.h>.  Most are just a
left over from __devinit and __cpuinit removal, or simply due to
code getting copied from one driver to the next.

The one instance where we add an include for init.h covers off
a case where that file was implicitly getting it from another
header which itself didn't need it.

Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---

[ build tested for every arch/powerpc/config/* file, on next
  branch of benh/powerpc.git -- v3.13-rc1-92-gdece8ada993e ]

 arch/powerpc/include/asm/paca.h                | 1 -
 arch/powerpc/include/asm/ppc_asm.h             | 1 -
 arch/powerpc/include/asm/ps3.h                 | 1 -
 arch/powerpc/include/asm/vio.h                 | 1 -
 arch/powerpc/kernel/cacheinfo.c                | 1 -
 arch/powerpc/kernel/crash.c                    | 1 -
 arch/powerpc/kernel/eeh_pe.c                   | 1 -
 arch/powerpc/kernel/head_64.S                  | 1 +
 arch/powerpc/kernel/hw_breakpoint.c            | 1 -
 arch/powerpc/kernel/iomap.c                    | 1 -
 arch/powerpc/kernel/kgdb.c                     | 1 -
 arch/powerpc/kernel/process.c                  | 1 -
 arch/powerpc/kernel/smp-tbsync.c               | 1 -
 arch/powerpc/kernel/syscalls.c                 | 1 -
 arch/powerpc/kernel/vdso32/vdso32_wrapper.S    | 1 -
 arch/powerpc/kernel/vdso64/vdso64_wrapper.S    | 1 -
 arch/powerpc/mm/pgtable.c                      | 1 -
 arch/powerpc/mm/pgtable_64.c                   | 1 -
 arch/powerpc/mm/tlb_hash64.c                   | 1 -
 arch/powerpc/oprofile/op_model_7450.c          | 1 -
 arch/powerpc/oprofile/op_model_cell.c          | 1 -
 arch/powerpc/oprofile/op_model_fsl_emb.c       | 1 -
 arch/powerpc/oprofile/op_model_pa6t.c          | 1 -
 arch/powerpc/oprofile/op_model_power4.c        | 1 -
 arch/powerpc/oprofile/op_model_rs64.c          | 1 -
 arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c | 1 -
 arch/powerpc/platforms/83xx/suspend.c          | 1 -
 arch/powerpc/platforms/85xx/sgy_cts1000.c      | 1 -
 arch/powerpc/platforms/chrp/smp.c              | 1 -
 arch/powerpc/platforms/embedded6xx/hlwd-pic.c  | 1 -
 arch/powerpc/platforms/pasemi/dma_lib.c        | 1 -
 arch/powerpc/platforms/powermac/pfunc_core.c   | 1 -
 arch/powerpc/platforms/powernv/eeh-ioda.c      | 1 -
 arch/powerpc/platforms/pseries/cmm.c           | 1 -
 arch/powerpc/platforms/pseries/dtl.c           | 1 -
 arch/powerpc/sysdev/cpm2_pic.c                 | 1 -
 arch/powerpc/sysdev/fsl_ifc.c                  | 1 -
 arch/powerpc/sysdev/ge/ge_pic.h                | 1 -
 arch/powerpc/sysdev/i8259.c                    | 1 -
 arch/powerpc/sysdev/mpc8xx_pic.c               | 1 -
 arch/powerpc/sysdev/qe_lib/qe_io.c             | 1 -
 arch/powerpc/sysdev/qe_lib/ucc.c               | 1 -
 arch/powerpc/sysdev/qe_lib/ucc_fast.c          | 1 -
 arch/powerpc/sysdev/qe_lib/ucc_slow.c          | 1 -
 arch/powerpc/sysdev/udbg_memcons.c             | 1 -
 arch/powerpc/sysdev/xics/icp-hv.c              | 1 -
 46 files changed, 1 insertion(+), 45 deletions(-)

diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index c3523d1dda58..68bee4636045 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -16,7 +16,6 @@
 
 #ifdef CONFIG_PPC64
 
-#include <linux/init.h>
 #include <asm/types.h>
 #include <asm/lppaca.h>
 #include <asm/mmu.h>
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index f595b98079ee..7689e0e98d33 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -4,7 +4,6 @@
 #ifndef _ASM_POWERPC_PPC_ASM_H
 #define _ASM_POWERPC_PPC_ASM_H
 
-#include <linux/init.h>
 #include <linux/stringify.h>
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index 678a7c1d9cb8..a1bc7e758422 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -21,7 +21,6 @@
 #if !defined(_ASM_POWERPC_PS3_H)
 #define _ASM_POWERPC_PS3_H
 
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
 #include <asm/cell-pmu.h>
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 68d0cc998b1b..4f9b7ca0710f 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -15,7 +15,6 @@
 #define _ASM_POWERPC_VIO_H
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 654932727873..abfa011344d9 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -12,7 +12,6 @@
 
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index fdcd8f551aff..18d7c80ddeb9 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -17,7 +17,6 @@
 #include <linux/export.h>
 #include <linux/crash_dump.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/types.h>
 
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index f9450537e335..1feccd64f955 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/string.h>
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 4f0946de2d5c..b7363bd42452 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -23,6 +23,7 @@
  */
 
 #include <linux/threads.h>
+#include <linux/init.h>
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index f0b47d1a6b0e..b0a1792279bb 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -28,7 +28,6 @@
 #include <linux/percpu.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/hw_breakpoint.h>
diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index 97a3715ac8bd..b82227e7e21b 100644
--- a/arch/powerpc/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
@@ -3,7 +3,6 @@
  *
  * (C) Copyright 2004 Linus Torvalds
  */
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/mm.h>
 #include <linux/export.h>
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 83e89d310734..8504657379f1 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -15,7 +15,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/smp.h>
 #include <linux/signal.h>
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 3386d8ab7eb0..bf8e136316e2 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/elf.h>
-#include <linux/init.h>
 #include <linux/prctl.h>
 #include <linux/init_task.h>
 #include <linux/export.h>
diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c
index e68fd1ae727a..7a37ecd3afa3 100644
--- a/arch/powerpc/kernel/smp-tbsync.c
+++ b/arch/powerpc/kernel/smp-tbsync.c
@@ -9,7 +9,6 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/unistd.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/atomic.h>
 #include <asm/smp.h>
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index 4e3cc47f26b9..cd9be9aa016d 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -34,7 +34,6 @@
 #include <linux/ipc.h>
 #include <linux/utsname.h>
 #include <linux/file.h>
-#include <linux/init.h>
 #include <linux/personality.h>
 
 #include <asm/uaccess.h>
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
index 6e8f507ed32b..79683d0393f5 100644
--- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -1,4 +1,3 @@
-#include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/page.h>
 
diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
index b8553d62b792..8df9e2463007 100644
--- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
@@ -1,4 +1,3 @@
-#include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/page.h>
 
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index ad90429bbd8b..c695943a513c 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <linux/hugetlb.h>
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 02e8681fb865..7f0e872ab83d 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -33,7 +33,6 @@
 #include <linux/swap.h>
 #include <linux/stddef.h>
 #include <linux/vmalloc.h>
-#include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
index 36e44b4260eb..c99f6510a0b2 100644
--- a/arch/powerpc/mm/tlb_hash64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <asm/pgalloc.h>
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index ff617246d128..d29b6e4e5e72 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -16,7 +16,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index b9589c19ccda..1f0ebdeea5f7 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -16,7 +16,6 @@
 
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/kthread.h>
 #include <linux/oprofile.h>
diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c
index 2a82d3ed464d..14cf86fdddab 100644
--- a/arch/powerpc/oprofile/op_model_fsl_emb.c
+++ b/arch/powerpc/oprofile/op_model_fsl_emb.c
@@ -14,7 +14,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
index 42f778dff919..a114a7c22d40 100644
--- a/arch/powerpc/oprofile/op_model_pa6t.c
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -22,7 +22,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/percpu.h>
 #include <asm/processor.h>
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index f444b94935f5..962fe7b3e3fb 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/firmware.h>
 #include <asm/ptrace.h>
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index 9b801b8c8c5a..7e5b8ed3a1b7 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -8,7 +8,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
index fd71cfdf2380..e238b6a55b15 100644
--- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
+++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
@@ -11,7 +11,6 @@
  * (at your option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
index 3d9716ccd327..4b4c081df94d 100644
--- a/arch/powerpc/platforms/83xx/suspend.c
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -10,7 +10,6 @@
  * by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
diff --git a/arch/powerpc/platforms/85xx/sgy_cts1000.c b/arch/powerpc/platforms/85xx/sgy_cts1000.c
index b9197cea1854..bb75add67084 100644
--- a/arch/powerpc/platforms/85xx/sgy_cts1000.c
+++ b/arch/powerpc/platforms/85xx/sgy_cts1000.c
@@ -14,7 +14,6 @@
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/workqueue.h>
diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c
index dead91b177b9..b6c9a0dcc924 100644
--- a/arch/powerpc/platforms/chrp/smp.c
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index 6c03034dbbd3..c269caee58f9 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -15,7 +15,6 @@
 #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c
index f3defd8a2806..aafa01ba062f 100644
--- a/arch/powerpc/platforms/pasemi/dma_lib.c
+++ b/arch/powerpc/platforms/pasemi/dma_lib.c
@@ -18,7 +18,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index d588e48dff74..43075081721f 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -5,7 +5,6 @@
  * FIXME: LOCKING !!!
  */
 
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 9b1db254898a..007ac4989841 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -14,7 +14,6 @@
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index 1e561bef459b..2d8bf15879fd 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/gfp.h>
-#include <linux/init.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/oom.h>
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index 5db66f1fbc26..7d61498e45c0 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -20,7 +20,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/spinlock.h>
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 10386b676d87..a11bd1d433ad 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -27,7 +27,6 @@
  */
 
 #include <linux/stddef.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/irq.h>
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
index d7fc72239144..fbc885b31946 100644
--- a/arch/powerpc/sysdev/fsl_ifc.c
+++ b/arch/powerpc/sysdev/fsl_ifc.c
@@ -19,7 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/compiler.h>
diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h
index 6149916da3f4..908dbd9826b6 100644
--- a/arch/powerpc/sysdev/ge/ge_pic.h
+++ b/arch/powerpc/sysdev/ge/ge_pic.h
@@ -1,7 +1,6 @@
 #ifndef __GEF_PIC_H__
 #define __GEF_PIC_H__
 
-#include <linux/init.h>
 
 void gef_pic_cascade(unsigned int, struct irq_desc *);
 unsigned int gef_pic_get_irq(void);
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 997df6a7ab5d..45598da0b321 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -8,7 +8,6 @@
  */
 #undef DEBUG
 
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index b724622c3a0b..c4828c0be5bd 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -1,6 +1,5 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/irq.h>
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index a88807b3dd57..d09994164daf 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -16,7 +16,6 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
index 134b07d29435..621575b7e84a 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -14,7 +14,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index cceb2e366738..65aaf15032ae 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -13,7 +13,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
index 1c062f48f1ac..befaf1123f7f 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -13,7 +13,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c
index ce5a7b489e4b..9998c0de12d0 100644
--- a/arch/powerpc/sysdev/udbg_memcons.c
+++ b/arch/powerpc/sysdev/udbg_memcons.c
@@ -18,7 +18,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/barrier.h>
 #include <asm/page.h>
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
index df0fc5821469..c1917cf67c3d 100644
--- a/arch/powerpc/sysdev/xics/icp-hv.c
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -12,7 +12,6 @@
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/of.h>
 
-- 
1.8.5.2

^ permalink raw reply related

* [PATCH] ASoC: fsl_esai: Add ESAI CPU DAI driver
From: Nicolin Chen @ 2014-01-09  9:10 UTC (permalink / raw)
  To: broonie, timur
  Cc: mark.rutland, devicetree, alsa-devel, pawel.moll, ijc+devicetree,
	tiwai, linux-kernel, linux-doc, lgirdwood, perex, robh+dt,
	Guangyu.Chen, rob, galak, grant.likely, shawn.guo, linuxppc-dev

This patch implements a device-tree-only CPU DAI driver for Freescale ESAI
controller that supports:

 - 12 channels playback and 8 channels record.
   [ Some of the inner transmitters and receivers are sharing same group of
     pins. So the maxmium 12 output or 8 input channels are only valid if
     there is no pin conflict occurring to it. ]

 - Independent (asynchronous mode) or shared (synchronous mode) transmit and
   receive sections with separate or shared internal/external clocks and frame
   syncs, operating in Master or Slave mode.
   [ Current ALSA seems not to allow CPU DAI drivers to set DAI format and clks
     separately for PLAYBACK and CAPTURE. So this first version only supports
     the case that uses the same DAI format for both directions. ]

 - Various DAI formats: I2S, Left-Justified, Right-Justified, DSP-A and DSP-B.

 - Programmable word length (8, 16, 20 or 24bits)

 - Flexible selection between system clock or external oscillator as input
   clock source, programmable internal clock divider and frame sync generation.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
 .../devicetree/bindings/sound/fsl,esai.txt         |  54 ++
 sound/soc/fsl/Kconfig                              |   3 +
 sound/soc/fsl/Makefile                             |   2 +
 sound/soc/fsl/fsl_esai.c                           | 811 +++++++++++++++++++++
 sound/soc/fsl/fsl_esai.h                           | 348 +++++++++
 5 files changed, 1218 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,esai.txt
 create mode 100644 sound/soc/fsl/fsl_esai.c
 create mode 100644 sound/soc/fsl/fsl_esai.h

diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
new file mode 100644
index 0000000..4372833
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -0,0 +1,54 @@
+Freescale Enhanced Serial Audio Interface (ESAI) Controller
+
+The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
+for serial communication with a variety of serial devices, including industry
+standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
+other DSPs. It has up to six transmitters and four receivers.
+
+Required properties:
+
+  - compatible : Compatible list, must contain "fsl,imx35-esai".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks: Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"core"		The core clock used to access registers
+	"extal"		The esai baud clock for esai controller used to derive
+			HCK, SCK and FS.
+	"fsys"		The system clock derived from ahb clock used to derive
+			HCK, SCK and FS.
+
+  - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
+    This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
+
+  - fsl,esai-synchronous: This is a boolean property. If present, indicating
+    that ESAI would work in the synchronous mode, which means all the settings
+    for Receiving would be duplicated from Transmition related registers.
+
+  - fsl,esai-network-mode: This is a boolean property. If present, indicating
+    that ESAI controller would work in its network mode.
+
+Example:
+
+esai: esai@02024000 {
+	compatible = "fsl,imx35-esai";
+	reg = <0x02024000 0x4000>;
+	interrupts = <0 51 0x04>;
+	clocks = <&clks 208>, <&clks 118>, <&clks 208>;
+	clock-names = "core", "extal", "fsys";
+	dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
+	dma-names = "rx", "tx";
+	fsl,fifo-depth = <128>;
+	fsl,esai-synchronous;
+	fsl,esai-network-mode;
+	status = "disabled";
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 514c275..324988d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -8,6 +8,9 @@ config SND_SOC_FSL_SSI
 config SND_SOC_FSL_SPDIF
 	tristate
 
+config SND_SOC_FSL_ESAI
+	tristate
+
 config SND_SOC_FSL_UTILS
 	tristate
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index aaccbee..b12ad4b 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -14,11 +14,13 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-spdif-objs := fsl_spdif.o
+snd-soc-fsl-esai-objs := fsl_esai.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
 obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
+obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644
index 0000000..1f2a0ef
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.c
@@ -0,0 +1,811 @@
+/*
+ * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_esai.h"
+#include "imx-pcm.h"
+
+#define FSL_ESAI_RATES		SNDRV_PCM_RATE_8000_192000
+#define FSL_ESAI_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
+				SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S20_3LE | \
+				SNDRV_PCM_FMTBIT_S24_LE)
+
+/*
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @coreclk: clock source to access register
+ * @extalclk: esai clock source to derive HCK, SCK and FS
+ * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @fifo_depth: depth of tx/rx FIFO
+ * @sck_div: if using PSR/PM dividers for SCK clock
+ * @network_mode: if using network mode
+ * @synchronous: if using tx/rx synchronous mode
+ * @name: driver name
+ */
+struct fsl_esai {
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *coreclk;
+	struct clk *extalclk;
+	struct clk *fsysclk;
+	u32 fifo_depth;
+	u32 slot_width;
+	bool sck_div;
+	bool network_mode;
+	bool synchronous;
+	char name[32];
+};
+
+static irqreturn_t esai_isr(int irq, void *devid)
+{
+	struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
+	struct platform_device *pdev = esai_priv->pdev;
+	u32 esr;
+
+	regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
+
+	if (esr & ESAI_ESR_TINIT_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
+
+	if (esr & ESAI_ESR_RFF_MASK)
+		dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+
+	if (esr & ESAI_ESR_TFE_MASK)
+		dev_warn(&pdev->dev, "isr: Transmition underrun\n");
+
+	if (esr & ESAI_ESR_TLS_MASK)
+		dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
+
+	if (esr & ESAI_ESR_TDE_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
+
+	if (esr & ESAI_ESR_TED_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
+
+	if (esr & ESAI_ESR_TD_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmitting data\n");
+
+	if (esr & ESAI_ESR_RLS_MASK)
+		dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
+
+	if (esr & ESAI_ESR_RDE_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
+
+	if (esr & ESAI_ESR_RED_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
+
+	if (esr & ESAI_ESR_RD_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving data\n");
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * This function is used to calculate the divisors of psr, pm, fp and it is
+ * supposed to be called in set_dai_sysclk() and set_bclk_ratio().
+ *
+ * @ratio: desired overall ratio for the paticipating dividers
+ * @usefp: for HCK setting, there is no need to set fp divider
+ * @fp: bypass other dividers by setting fp directly if fp != 0
+ */
+static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, u32 ratio,
+				bool usefp, u32 fp)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
+
+	maxfp = usefp ? 16 : 1;
+
+	if (usefp && fp)
+		goto out_fp;
+
+	if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
+		dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
+				2 * 8 * 256 * maxfp);
+		return -EINVAL;
+	} else if (ratio % 2) {
+		dev_err(dai->dev, "the raio must be even if using upper divider\n");
+		return -EINVAL;
+	}
+
+	ratio /= 2;
+
+	psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
+
+	/* Set the max fluctuation -- 0.1% of the max devisor */
+	savesub = (psr ? 1 : 8)  * 256 * maxfp / 1000;
+
+	/* Find the best value for PM */
+	for (i = 1; i <= 256; i++) {
+		for (j = 1; j <= maxfp; j++) {
+			/* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
+			prod = (psr ? 1 : 8) * i * j;
+
+			if (prod == ratio)
+				sub = 0;
+			else if (prod / ratio == 1)
+				sub = prod - ratio;
+			else if (ratio / prod == 1)
+				sub = ratio - prod;
+			else
+				continue;
+
+			/* Calculate the fraction */
+			sub = sub * 1000 / ratio;
+			if (sub < savesub) {
+				savesub = sub;
+				pm = i;
+				fp = j;
+			}
+
+			/* We are lucky */
+			if (savesub == 0)
+				goto out;
+		}
+	}
+
+	if (pm == 999) {
+		dev_err(dai->dev, "failed to calculate proper divisors\n");
+		return -EINVAL;
+	}
+
+out:
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+			   psr | ESAI_xCCR_xPM(pm));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+			   psr | ESAI_xCCR_xPM(pm));
+
+out_fp:
+	/* Bypass fp if not being required */
+	if (maxfp <= 1)
+		return 0;
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+
+	return 0;
+}
+
+/*
+ * This function mainly configures the clock frequency of MCLK (HCK)
+ *
+ * @Parameters:
+ * clk_id: The clock source of HCK
+ *	  (Input from outside; output from inside, FSYS or EXTAL)
+ * freq: The required clock rate of HCK
+ * dir: The clock direction of HCK
+ *
+ * Note: If the direction is input, we do not care about clk_id.
+ */
+static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				   unsigned int freq, int dir)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool in = dir == SND_SOC_CLOCK_IN;
+	u32 ret, ratio, ecr = 0;
+	unsigned long clk_rate;
+
+	/* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
+	esai_priv->sck_div = true;
+
+	/* Set the direction of HCK pins */
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xHCKD, in ? 0: ESAI_xCCR_xHCKD);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xHCKD, in ? 0: ESAI_xCCR_xHCKD);
+
+	if (in)
+		goto out;
+
+	switch (clk_id) {
+	case ESAI_HCK_FSYS:
+		if (IS_ERR(esai_priv->fsysclk)) {
+			dev_err(dai->dev, "no assigned fsys clock\n");
+			return -EINVAL;
+		}
+		clk_rate = clk_get_rate(esai_priv->fsysclk);
+		break;
+	case ESAI_HCK_EXTAL:
+		if (IS_ERR(esai_priv->extalclk)) {
+			dev_err(dai->dev, "no assigned extal clock\n");
+			return -EINVAL;
+		}
+		clk_rate = clk_get_rate(esai_priv->extalclk);
+
+		ecr |= ESAI_ECR_ETI | ESAI_ECR_ERI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ratio = clk_rate / freq;
+	if (ratio * freq > clk_rate)
+		ret = ratio * freq - clk_rate;
+	else if (ratio * freq < clk_rate)
+		ret = clk_rate - ratio * freq;
+	else
+		ret = 0;
+
+	/* Block if clock source can not be divided into the required rate */
+	if (ret != 0 && clk_rate / ret < 1000) {
+		dev_err(dai->dev, "failed to derive the required frequency\n");
+		return -EINVAL;
+	}
+
+	if (ratio == 1) {
+		/* Bypass all the dividers if not being needed */
+		ecr |= ESAI_ECR_ETO | ESAI_ECR_ERO;
+		goto out;
+	}
+
+	ret = fsl_esai_divisor_cal(dai, ratio, false, 0);
+	if (ret)
+		return ret;
+
+	esai_priv->sck_div = false;
+
+out:
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
+			   ESAI_ECR_ETI | ESAI_ECR_ETO |
+			   ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
+
+	return 0;
+}
+
+/*
+ * This function configures the ratio between MCLK (HCK) and BCLK (SCK)
+ * (For DAI Master Mode only)
+ *
+ * Note: Machine driver should calculate the ratio to call this function.
+ * 	 Only effective after calling set_dai_sysclk() to set HCK direction.
+ */
+static int fsl_esai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 fp = esai_priv->sck_div ? 0 : ratio;
+
+	if (!esai_priv->sck_div && (ratio > 16 || ratio == 0)) {
+		dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
+		return -EINVAL;
+	}
+
+	return fsl_esai_divisor_cal(dai, ratio, true, fp);
+}
+
+/*
+ * This function provides a manual way to configure all the dividers directly
+ * (For DAI Master Mode only)
+ *
+ * By using this function, the driver would allow user to configure a flexible
+ * combination of divisors for both TX and RX route separately
+ *
+ * Note: Only effective after calling set_dai_sysclk() to set HCK direction
+ */
+static int fsl_esai_set_dai_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = div_id <= ESAI_TX_DIV_FP;
+	u32 mask, val;
+
+	switch (div_id) {
+	case ESAI_TX_DIV_PSR:
+	case ESAI_RX_DIV_PSR:
+		mask = ESAI_xCCR_xPSR_MASK;
+		val = div ? ESAI_xCCR_xPSR_BYPASS : 0;
+		break;
+	case ESAI_TX_DIV_PM:
+	case ESAI_RX_DIV_PM:
+		mask = ESAI_xCCR_xPM_MASK;
+		val = ESAI_xCCR_xPM(div);
+		break;
+	case ESAI_TX_DIV_FP:
+	case ESAI_RX_DIV_FP:
+		mask = ESAI_xCCR_xFP_MASK;
+		val = ESAI_xCCR_xFP(div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx), mask, val);
+}
+
+static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
+				     u32 rx_mask, int slots, int slot_width)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+
+	esai_priv->slot_width = slot_width;
+
+	return 0;
+}
+
+static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 xcr = 0, xccr = 0, mask;
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* Data on rising edge of bclk, frame low, 1clk before data */
+		xcr |= ESAI_xCR_xFSR;
+		xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		/* Data on rising edge of bclk, frame high */
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		/* Data on rising edge of bclk, frame high, right aligned */
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* Data on rising edge of bclk, frame high, 1clk before data */
+		xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		/* Data on rising edge of bclk, frame high */
+		xcr |= ESAI_xCR_xFSL;
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* Nothing to do for both normal cases */
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		/* Invert bit clock */
+		xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		/* Invert frame clock */
+		xccr ^= ESAI_xCCR_xFSP;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Invert both clocks */
+		xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		xccr |= ESAI_xCCR_xCKD;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		xccr |= ESAI_xCCR_xFSD;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
+
+	mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
+		ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
+
+	return 0;
+}
+
+static int fsl_esai_startup(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	/* Some platforms might use the same bit to gate all three or two of
+	 * clocks, so keep all clocks open/close at the same time for safety
+	 */
+	clk_prepare_enable(esai_priv->coreclk);
+	if (!IS_ERR(esai_priv->extalclk))
+		clk_prepare_enable(esai_priv->extalclk);
+	if (!IS_ERR(esai_priv->fsysclk))
+		clk_prepare_enable(esai_priv->fsysclk);
+
+	if (!dai->active) {
+		/* Reset Port C */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
+				   ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
+				   ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
+
+		/* Set synchronous mode */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
+				   ESAI_SAICR_SYNC, esai_priv->synchronous ?
+				   ESAI_SAICR_SYNC : 0);
+
+		/* Set network mode */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
+				   ESAI_xCR_xMOD_MASK, esai_priv->network_mode ?
+				   ESAI_xCR_xMOD_NETWORK : 0);
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
+				   ESAI_xCR_xMOD_MASK, esai_priv->network_mode ?
+				   ESAI_xCR_xMOD_NETWORK : 0);
+
+		/* Set a default slot number -- 2 */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+				   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+				   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+	}
+
+	return 0;
+}
+
+static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 width = snd_pcm_format_width(params_format(params));
+	u32 channels = params_channels(params);
+	u32 mask, val;
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+			   ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
+
+	mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
+	      (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
+	val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth / 2) |
+	     (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
+
+	mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
+	val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+
+	return 0;
+}
+
+static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	if (!IS_ERR(esai_priv->fsysclk))
+		clk_disable_unprepare(esai_priv->fsysclk);
+	if (!IS_ERR(esai_priv->extalclk))
+		clk_disable_unprepare(esai_priv->extalclk);
+	clk_disable_unprepare(esai_priv->coreclk);
+}
+
+static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u8 i, channels = substream->runtime->channels;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
+
+		/* Write initial words reqiured by ESAI as normal procedure */
+		for (i = 0; tx && i < channels; i++)
+			regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
+
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+				   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
+				   tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+				   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
+
+		/* Disable and reset FIFO */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFR, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+	.startup = fsl_esai_startup,
+	.shutdown = fsl_esai_shutdown,
+	.trigger = fsl_esai_trigger,
+	.hw_params = fsl_esai_hw_params,
+	.set_sysclk = fsl_esai_set_dai_sysclk,
+	.set_bclk_ratio = fsl_esai_set_bclk_ratio,
+	.set_clkdiv = fsl_esai_set_dai_clkdiv,
+	.set_fmt = fsl_esai_set_dai_fmt,
+	.set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
+static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
+				  &esai_priv->dma_params_rx);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+	.probe = fsl_esai_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 12,
+		.rates = FSL_ESAI_RATES,
+		.formats = FSL_ESAI_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = FSL_ESAI_RATES,
+		.formats = FSL_ESAI_FORMATS,
+	},
+	.ops = &fsl_esai_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_esai_component = {
+	.name		= "fsl-esai",
+};
+
+static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_ESAI_ERDR:
+	case REG_ESAI_ECR:
+	case REG_ESAI_ESR:
+	case REG_ESAI_TFCR:
+	case REG_ESAI_TFSR:
+	case REG_ESAI_RFCR:
+	case REG_ESAI_RFSR:
+	case REG_ESAI_RX0:
+	case REG_ESAI_RX1:
+	case REG_ESAI_RX2:
+	case REG_ESAI_RX3:
+	case REG_ESAI_SAISR:
+	case REG_ESAI_SAICR:
+	case REG_ESAI_TCR:
+	case REG_ESAI_TCCR:
+	case REG_ESAI_RCR:
+	case REG_ESAI_RCCR:
+	case REG_ESAI_TSMA:
+	case REG_ESAI_TSMB:
+	case REG_ESAI_RSMA:
+	case REG_ESAI_RSMB:
+	case REG_ESAI_PRRC:
+	case REG_ESAI_PCRC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_ESAI_ETDR:
+	case REG_ESAI_ECR:
+	case REG_ESAI_TFCR:
+	case REG_ESAI_RFCR:
+	case REG_ESAI_TX0:
+	case REG_ESAI_TX1:
+	case REG_ESAI_TX2:
+	case REG_ESAI_TX3:
+	case REG_ESAI_TX4:
+	case REG_ESAI_TX5:
+	case REG_ESAI_TSR:
+	case REG_ESAI_SAICR:
+	case REG_ESAI_TCR:
+	case REG_ESAI_TCCR:
+	case REG_ESAI_RCR:
+	case REG_ESAI_RCCR:
+	case REG_ESAI_TSMA:
+	case REG_ESAI_TSMB:
+	case REG_ESAI_RSMA:
+	case REG_ESAI_RSMB:
+	case REG_ESAI_PRRC:
+	case REG_ESAI_PCRC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config fsl_esai_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = REG_ESAI_PCRC,
+	.readable_reg = fsl_esai_readable_reg,
+	.writeable_reg = fsl_esai_writeable_reg,
+};
+
+static int fsl_esai_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_esai *esai_priv;
+	struct resource *res;
+	const uint32_t *iprop;
+	void __iomem *regs;
+	int irq, ret;
+
+	esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
+	if (!esai_priv)
+		return -ENOMEM;
+
+	esai_priv->pdev = pdev;
+	strcpy(esai_priv->name, np->name);
+
+	/* Get the addresses and IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+			"core", regs, &fsl_esai_regmap_config);
+	if (IS_ERR(esai_priv->regmap)) {
+		dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+				PTR_ERR(esai_priv->regmap));
+		return PTR_ERR(esai_priv->regmap);
+	}
+
+	esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+	if (IS_ERR(esai_priv->coreclk)) {
+		dev_err(&pdev->dev, "failed to get core clock: %ld\n",
+				PTR_ERR(esai_priv->coreclk));
+		return PTR_ERR(esai_priv->coreclk);
+	}
+
+	esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
+	if (IS_ERR(esai_priv->extalclk))
+		dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
+				PTR_ERR(esai_priv->extalclk));
+
+	esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
+	if (IS_ERR(esai_priv->fsysclk))
+		dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
+				PTR_ERR(esai_priv->fsysclk));
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
+			       esai_priv->name, esai_priv);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+		return ret;
+	}
+
+	/* Set a default slot size */
+	esai_priv->slot_width = 32;
+
+	/* Determine the FIFO depth */
+	iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+	if (iprop)
+		esai_priv->fifo_depth = be32_to_cpup(iprop);
+	else
+		esai_priv->fifo_depth = 64;
+
+	esai_priv->dma_params_tx.maxburst = esai_priv->fifo_depth > 1;
+	esai_priv->dma_params_rx.maxburst = esai_priv->fifo_depth > 1;
+	esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
+	esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
+
+	esai_priv->synchronous =
+		of_property_read_bool(np, "fsl,esai-synchronous");
+	esai_priv->network_mode =
+		of_property_read_bool(np, "fsl,esai-network-mode");
+
+	dev_set_drvdata(&pdev->dev, esai_priv);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
+					      &fsl_esai_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+		return ret;
+	}
+
+	ret = imx_pcm_dma_init(pdev);
+	if (ret)
+		dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+	/* Reset ESAI unit */
+	regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
+
+	/* We need to enable ESAI so as to access some of its registers.
+	 * Otherwise, we would fail to dump regmap from user space.
+	 */
+	regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
+
+	return ret;
+}
+
+static const struct of_device_id fsl_esai_dt_ids[] = {
+	{ .compatible = "fsl,imx35-esai", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
+
+static struct platform_driver fsl_esai_driver = {
+	.probe = fsl_esai_probe,
+	.driver = {
+		.name = "fsl-esai-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_esai_dt_ids,
+	},
+};
+
+module_platform_driver(fsl_esai_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-esai-dai");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644
index 0000000..707189d
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.h
@@ -0,0 +1,348 @@
+/*
+ * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_ESAI_DAI_H
+#define _FSL_ESAI_DAI_H
+
+/* ESAI Register Map */
+#define REG_ESAI_ETDR		0x00
+#define REG_ESAI_ERDR		0x04
+#define REG_ESAI_ECR		0x08
+#define REG_ESAI_ESR		0x0C
+#define REG_ESAI_TFCR		0x10
+#define REG_ESAI_TFSR		0x14
+#define REG_ESAI_RFCR		0x18
+#define REG_ESAI_RFSR		0x1C
+#define REG_ESAI_xFCR(tx)	(tx ? REG_ESAI_TFCR : REG_ESAI_RFCR)
+#define REG_ESAI_xFSR(tx)	(tx ? REG_ESAI_TFSR : REG_ESAI_RFSR)
+#define REG_ESAI_TX0		0x80
+#define REG_ESAI_TX1		0x84
+#define REG_ESAI_TX2		0x88
+#define REG_ESAI_TX3		0x8C
+#define REG_ESAI_TX4		0x90
+#define REG_ESAI_TX5		0x94
+#define REG_ESAI_TSR		0x98
+#define REG_ESAI_RX0		0xA0
+#define REG_ESAI_RX1		0xA4
+#define REG_ESAI_RX2		0xA8
+#define REG_ESAI_RX3		0xAC
+#define REG_ESAI_SAISR		0xCC
+#define REG_ESAI_SAICR		0xD0
+#define REG_ESAI_TCR		0xD4
+#define REG_ESAI_TCCR		0xD8
+#define REG_ESAI_RCR		0xDC
+#define REG_ESAI_RCCR		0xE0
+#define REG_ESAI_xCR(tx)	(tx ? REG_ESAI_TCR : REG_ESAI_RCR)
+#define REG_ESAI_xCCR(tx)	(tx ? REG_ESAI_TCCR : REG_ESAI_RCCR)
+#define REG_ESAI_TSMA		0xE4
+#define REG_ESAI_TSMB		0xE8
+#define REG_ESAI_RSMA		0xEC
+#define REG_ESAI_RSMB		0xF0
+#define REG_ESAI_xSMA(tx)	(tx ? REG_ESAI_TSMA : REG_ESAI_RSMA)
+#define REG_ESAI_xSMB(tx)	(tx ? REG_ESAI_TSMB : REG_ESAI_RSMB)
+#define REG_ESAI_PRRC		0xF8
+#define REG_ESAI_PCRC		0xFC
+
+/* ESAI Control Register -- REG_ESAI_ECR 0x8 */
+#define ESAI_ECR_ETI_SHIFT	19
+#define ESAI_ECR_ETI_MASK	(1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETI		(1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETO_SHIFT	18
+#define ESAI_ECR_ETO_MASK	(1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ETO		(1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ERI_SHIFT	17
+#define ESAI_ECR_ERI_MASK	(1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERI		(1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERO_SHIFT	16
+#define ESAI_ECR_ERO_MASK	(1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERO		(1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERST_SHIFT	1
+#define ESAI_ECR_ERST_MASK	(1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ERST		(1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ESAIEN_SHIFT	0
+#define ESAI_ECR_ESAIEN_MASK	(1 << ESAI_ECR_ESAIEN_SHIFT)
+#define ESAI_ECR_ESAIEN		(1 << ESAI_ECR_ESAIEN_SHIFT)
+
+/* ESAI Status Register -- REG_ESAI_ESR 0xC */
+#define ESAI_ESR_TINIT_SHIFT	10
+#define ESAI_ESR_TINIT_MASK	(1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_TINIT		(1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_RFF_SHIFT	9
+#define ESAI_ESR_RFF_MASK	(1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_RFF		(1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_TFE_SHIFT	8
+#define ESAI_ESR_TFE_MASK	(1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TFE		(1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TLS_SHIFT	7
+#define ESAI_ESR_TLS_MASK	(1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TLS		(1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TDE_SHIFT	6
+#define ESAI_ESR_TDE_MASK	(1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TDE		(1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TED_SHIFT	5
+#define ESAI_ESR_TED_MASK	(1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TED		(1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TD_SHIFT	4
+#define ESAI_ESR_TD_MASK	(1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_TD		(1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_RLS_SHIFT	3
+#define ESAI_ESR_RLS_MASK	(1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RLS		(1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RDE_SHIFT	2
+#define ESAI_ESR_RDE_MASK	(1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RDE		(1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RED_SHIFT	1
+#define ESAI_ESR_RED_MASK	(1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RED		(1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RD_SHIFT	0
+#define ESAI_ESR_RD_MASK	(1 << ESAI_ESR_RD_SHIFT)
+#define ESAI_ESR_RD		(1 << ESAI_ESR_RD_SHIFT)
+
+/* Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10
+ * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18
+ */
+#define ESAI_xFCR_TIEN_SHIFT	19
+#define ESAI_xFCR_TIEN_MASK	(1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_TIEN		(1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_REXT_SHIFT	19
+#define ESAI_xFCR_REXT_MASK	(1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_REXT		(1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_xWA_SHIFT	16
+#define ESAI_xFCR_xWA_WIDTH	3
+#define ESAI_xFCR_xWA_MASK	(((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT)
+#define ESAI_xFCR_xWA(v)	(((8 - (v >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK)
+#define ESAI_xFCR_xFWM_SHIFT	8
+#define ESAI_xFCR_xFWM_WIDTH	8
+#define ESAI_xFCR_xFWM_MASK	(((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT)
+#define ESAI_xFCR_xFWM(v)	(((v - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK)
+#define ESAI_xFCR_xE_SHIFT	2
+#define ESAI_xFCR_TE_WIDTH	6
+#define ESAI_xFCR_RE_WIDTH	4
+#define ESAI_xFCR_TE_MASK	(((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_RE_MASK	(((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_TE(x) 	((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x) 	((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_xFR_SHIFT	1
+#define ESAI_xFCR_xFR_MASK	(1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFR		(1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFEN_SHIFT	0
+#define ESAI_xFCR_xFEN_MASK	(1 << ESAI_xFCR_xFEN_SHIFT)
+#define ESAI_xFCR_xFEN		(1 << ESAI_xFCR_xFEN_SHIFT)
+
+/* Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14
+ * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C
+ */
+#define ESAI_xFSR_NTFO_SHIFT	12
+#define ESAI_xFSR_NRFI_SHIFT	12
+#define ESAI_xFSR_NTFI_SHIFT	8
+#define ESAI_xFSR_NRFO_SHIFT	8
+#define ESAI_xFSR_NTFx_WIDTH	3
+#define ESAI_xFSR_NRFx_WIDTH	2
+#define ESAI_xFSR_NTFO_MASK	(((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT)
+#define ESAI_xFSR_NTFI_MASK	(((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT)
+#define ESAI_xFSR_NRFO_MASK	(((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT)
+#define ESAI_xFSR_NRFI_MASK	(((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT)
+#define ESAI_xFSR_xFCNT_SHIFT	0
+#define ESAI_xFSR_xFCNT_WIDTH	8
+#define ESAI_xFSR_xFCNT_MASK	(((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT)
+
+/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */
+#define ESAI_TSR_SHIFT		0
+#define ESAI_TSR_WIDTH		24
+#define ESAI_TSR_MASK		(((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT)
+
+/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */
+#define ESAI_SAISR_TODFE_SHIFT	17
+#define ESAI_SAISR_TODFE_MASK	(1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TODFE	(1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TEDE_SHIFT	16
+#define ESAI_SAISR_TEDE_MASK	(1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TEDE		(1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TDE_SHIFT	15
+#define ESAI_SAISR_TDE_MASK	(1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TDE		(1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TUE_SHIFT	14
+#define ESAI_SAISR_TUE_MASK	(1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TUE		(1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TFS_SHIFT	13
+#define ESAI_SAISR_TFS_MASK	(1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_TFS		(1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_RODF_SHIFT	10
+#define ESAI_SAISR_RODF_MASK	(1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_RODF		(1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_REDF_SHIFT	9
+#define ESAI_SAISR_REDF_MASK	(1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_REDF		(1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_RDF_SHIFT	8
+#define ESAI_SAISR_RDF_MASK	(1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_RDF		(1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_ROE_SHIFT	7
+#define ESAI_SAISR_ROE_MASK	(1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_ROE		(1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_RFS_SHIFT	6
+#define ESAI_SAISR_RFS_MASK	(1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_RFS		(1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_IF2_SHIFT	2
+#define ESAI_SAISR_IF2_MASK	(1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF2		(1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF1_SHIFT	1
+#define ESAI_SAISR_IF1_MASK	(1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF1		(1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF0_SHIFT	0
+#define ESAI_SAISR_IF0_MASK	(1 << ESAI_SAISR_IF0_SHIFT)
+#define ESAI_SAISR_IF0		(1 << ESAI_SAISR_IF0_SHIFT)
+
+/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */
+#define ESAI_SAICR_ALC_SHIFT	8
+#define ESAI_SAICR_ALC_MASK	(1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_ALC		(1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_TEBE_SHIFT	7
+#define ESAI_SAICR_TEBE_MASK	(1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_TEBE		(1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_SYNC_SHIFT	6
+#define ESAI_SAICR_SYNC_MASK	(1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_SYNC		(1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_OF2_SHIFT	2
+#define ESAI_SAICR_OF2_MASK	(1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF2		(1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF1_SHIFT	1
+#define ESAI_SAICR_OF1_MASK	(1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF1		(1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF0_SHIFT	0
+#define ESAI_SAICR_OF0_MASK	(1 << ESAI_SAICR_OF0_SHIFT)
+#define ESAI_SAICR_OF0		(1 << ESAI_SAICR_OF0_SHIFT)
+
+/* Transmit Control Register -- REG_ESAI_TCR 0xD4
+ * Receive Control Register -- REG_ESAI_RCR 0xDC
+ */
+#define ESAI_xCR_xLIE_SHIFT	23
+#define ESAI_xCR_xLIE_MASK	(1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xLIE		(1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xIE_SHIFT	22
+#define ESAI_xCR_xIE_MASK	(1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xIE		(1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xEDIE_SHIFT	21
+#define ESAI_xCR_xEDIE_MASK	(1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEDIE		(1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEIE_SHIFT	20
+#define ESAI_xCR_xEIE_MASK	(1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xEIE		(1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xPR_SHIFT	19
+#define ESAI_xCR_xPR_MASK	(1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_xPR		(1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_PADC_SHIFT	17
+#define ESAI_xCR_PADC_MASK	(1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_PADC		(1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_xFSR_SHIFT	16
+#define ESAI_xCR_xFSR_MASK	(1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSR		(1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSL_SHIFT	15
+#define ESAI_xCR_xFSL_MASK	(1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xFSL		(1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xSWS_SHIFT	10
+#define ESAI_xCR_xSWS_WIDTH	5
+#define ESAI_xCR_xSWS_MASK	(((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xSWS(s, w)	((w < 24 ? (s - w + ((w -8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xMOD_SHIFT	8
+#define ESAI_xCR_xMOD_WIDTH	2
+#define ESAI_xCR_xMOD_MASK	(((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_ONDEMAND	(0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_NETWORK	(0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_AC97	(0x3 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xWA_SHIFT	7
+#define ESAI_xCR_xWA_MASK	(1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xWA		(1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xSHFD_SHIFT	6
+#define ESAI_xCR_xSHFD_MASK	(1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xSHFD		(1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xE_SHIFT	0
+#define ESAI_xCR_TE_WIDTH	6
+#define ESAI_xCR_RE_WIDTH	4
+#define ESAI_xCR_TE_MASK	(((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_RE_MASK	(((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_TE(x) 		((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x) 		((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+
+/* Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
+ * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0
+ */
+#define ESAI_xCCR_xHCKD_SHIFT	23
+#define ESAI_xCCR_xHCKD_MASK	(1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xHCKD		(1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xFSD_SHIFT	22
+#define ESAI_xCCR_xFSD_MASK	(1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xFSD		(1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xCKD_SHIFT	21
+#define ESAI_xCCR_xCKD_MASK	(1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xCKD		(1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xHCKP_SHIFT	20
+#define ESAI_xCCR_xHCKP_MASK	(1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xHCKP		(1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xFSP_SHIFT	19
+#define ESAI_xCCR_xFSP_MASK	(1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xFSP		(1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xCKP_SHIFT	18
+#define ESAI_xCCR_xCKP_MASK	(1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xCKP		(1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xFP_SHIFT	14
+#define ESAI_xCCR_xFP_WIDTH	4
+#define ESAI_xCCR_xFP_MASK	(((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
+#define ESAI_xCCR_xFP(v)	(((v - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
+#define ESAI_xCCR_xDC_SHIFT     9
+#define ESAI_xCCR_xDC_WIDTH	4
+#define ESAI_xCCR_xDC_MASK	(((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
+#define ESAI_xCCR_xDC(v)	(((v - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
+#define ESAI_xCCR_xPSR_SHIFT	8
+#define ESAI_xCCR_xPSR_MASK	(1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_BYPASS	(1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_DIV8	(0 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPM_SHIFT     0
+#define ESAI_xCCR_xPM_WIDTH     8
+#define ESAI_xCCR_xPM_MASK	(((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT)
+#define ESAI_xCCR_xPM(v)	(((v - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK)
+
+/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 - 0xF0 */
+#define ESAI_xSMA_xS_SHIFT	0
+#define ESAI_xSMA_xS_WIDTH	16
+#define ESAI_xSMA_xS_MASK	(((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT)
+#define ESAI_xSMA_xS(v)		(v & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS_SHIFT	0
+#define ESAI_xSMB_xS_WIDTH	16
+#define ESAI_xSMB_xS_MASK	(((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
+#define ESAI_xSMB_xS(v)		((v >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+
+/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
+#define ESAI_PRRC_PDC_SHIFT	0
+#define ESAI_PRRC_PDC_WIDTH	12
+#define ESAI_PRRC_PDC_MASK	(((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT)
+#define ESAI_PRRC_PDC(v)	(v & ESAI_PRRC_PDC_MASK)
+
+/* Port C Control Register -- REG_ESAI_PCRC 0xFC */
+#define ESAI_PCRC_PC_SHIFT	0
+#define ESAI_PCRC_PC_WIDTH	12
+#define ESAI_PCRC_PC_MASK	(((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT)
+#define ESAI_PCRC_PC(v)		(v & ESAI_PCRC_PC_MASK)
+
+#define ESAI_GPIO		0xfff
+
+/* ESAI clock source */
+#define ESAI_HCK_FSYS		0
+#define ESAI_HCK_EXTAL		1
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR		0
+#define ESAI_TX_DIV_PM		1
+#define ESAI_TX_DIV_FP		2
+#define ESAI_RX_DIV_PSR		3
+#define ESAI_RX_DIV_PM		4
+#define ESAI_RX_DIV_FP		5
+#endif /* _FSL_ESAI_DAI_H */
-- 
1.8.4

^ permalink raw reply related

* [PATCH] ASoC: fsl_ssi: Set default slot number for common cases
From: Nicolin Chen @ 2014-01-09  9:41 UTC (permalink / raw)
  To: broonie, timur; +Cc: tiwai, alsa-devel, linuxppc-dev, lgirdwood, perex

For those platforms using DAI master mode like I2S, it's better to pre-set
a default slot number so that there's no need for these common cases to set
the slot number from its machine driver any more.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
 sound/soc/fsl/fsl_ssi.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 94dedcb..57ab45b 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -711,6 +711,16 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
 	if (ssi_private->imx_ac97)
 		fsl_ssi_setup_ac97(ssi_private);
 
+	/* Set a default slot number so that there is no need for those common
+	 * cases like I2S mode to call the extra set_tdm_slot() any more.
+	 */
+	if (!ssi_private->imx_ac97) {
+		write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+				CCSR_SSI_SxCCR_DC(2));
+		write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+				CCSR_SSI_SxCCR_DC(2));
+	}
+
 	return 0;
 }
 
-- 
1.8.4

^ permalink raw reply related

* Re: [alsa-devel] [PATCH] ASoC: fsl_ssi: Set default slot number for common cases
From: Fabio Estevam @ 2014-01-09 10:24 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: alsa-devel@alsa-project.org, Takashi Iwai, Timur Tabi,
	Liam Girdwood, Mark Brown, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1389260514-11365-1-git-send-email-Guangyu.Chen@freescale.com>

On Thu, Jan 9, 2014 at 7:41 AM, Nicolin Chen <Guangyu.Chen@freescale.com> wrote:
> For those platforms using DAI master mode like I2S, it's better to pre-set
> a default slot number so that there's no need for these common cases to set
> the slot number from its machine driver any more.
>
> Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
> ---
>  sound/soc/fsl/fsl_ssi.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> index 94dedcb..57ab45b 100644
> --- a/sound/soc/fsl/fsl_ssi.c
> +++ b/sound/soc/fsl/fsl_ssi.c
> @@ -711,6 +711,16 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
>         if (ssi_private->imx_ac97)
>                 fsl_ssi_setup_ac97(ssi_private);
>
> +       /* Set a default slot number so that there is no need for those common
> +        * cases like I2S mode to call the extra set_tdm_slot() any more.
> +        */

Incorrect style for multi-line comment.

Regards,

Fabio Estevam

^ permalink raw reply

* Re: [alsa-devel] [PATCH] ASoC: fsl_ssi: Set default slot number for common cases
From: Nicolin Chen @ 2014-01-09 10:34 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: alsa-devel@alsa-project.org, Takashi Iwai, Timur Tabi,
	Liam Girdwood, Mark Brown, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <CAOMZO5C8hGYehqJ6WFUKye8wENuAejT-YXggeYy7V+DQ2_OMHg@mail.gmail.com>

Hi Fabio,

On Thu, Jan 09, 2014 at 08:24:24AM -0200, Fabio Estevam wrote:
> On Thu, Jan 9, 2014 at 7:41 AM, Nicolin Chen <Guangyu.Chen@freescale.com> wrote:
> > For those platforms using DAI master mode like I2S, it's better to pre-set
> > a default slot number so that there's no need for these common cases to set
> > the slot number from its machine driver any more.
> >
> > Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
> > ---
> >  sound/soc/fsl/fsl_ssi.c | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> >
> > diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
> > index 94dedcb..57ab45b 100644
> > --- a/sound/soc/fsl/fsl_ssi.c
> > +++ b/sound/soc/fsl/fsl_ssi.c
> > @@ -711,6 +711,16 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
> >         if (ssi_private->imx_ac97)
> >                 fsl_ssi_setup_ac97(ssi_private);
> >
> > +       /* Set a default slot number so that there is no need for those common
> > +        * cases like I2S mode to call the extra set_tdm_slot() any more.
> > +        */
> 
> Incorrect style for multi-line comment.

Is this for the initial line? The CodingStyle contains two types of multi-line
comment, one of which drops the initial line just like mine, even though it's
saying 'For files in net/ and drivers/net/ the preferred style', so I thought
it shouldn't be quite bother.

I don't mind to add it up though.

Thank you,
Nicolin

^ permalink raw reply

* Re: [alsa-devel] [PATCH] ASoC: fsl_ssi: Set default slot number for common cases
From: Fabio Estevam @ 2014-01-09 10:40 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: alsa-devel@alsa-project.org, Takashi Iwai, Timur Tabi,
	Liam Girdwood, Mark Brown, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20140109103453.GC14809@MrMyself>

On Thu, Jan 9, 2014 at 8:34 AM, Nicolin Chen <Guangyu.Chen@freescale.com> wrote:

> Is this for the initial line? The CodingStyle contains two types of multi-line

Yes, correct.

> comment, one of which drops the initial line just like mine, even though it's
> saying 'For files in net/ and drivers/net/ the preferred style', so I thought
> it shouldn't be quite bother.

Yes, net and drivers/net are different and checkpatch reports it accordingly.

Regards,

Fabio Estevam

^ permalink raw reply

* [PATCH v2] ASoC: fsl_ssi: Set default slot number for common cases
From: Nicolin Chen @ 2014-01-09 10:42 UTC (permalink / raw)
  To: broonie, timur
  Cc: alsa-devel, tiwai, linuxppc-dev, lgirdwood, perex, festevam

For those platforms using DAI master mode like I2S, it's better to pre-set
a default slot number so that there's no need for these common cases to set
the slot number from its machine driver any more.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---

Changelog
v2:
 * Correct coding style for multi-line comment.

 sound/soc/fsl/fsl_ssi.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 94dedcb..aad2a1f 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -711,6 +711,17 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
 	if (ssi_private->imx_ac97)
 		fsl_ssi_setup_ac97(ssi_private);
 
+	/*
+	 * Set a default slot number so that there is no need for those common
+	 * cases like I2S mode to call the extra set_tdm_slot() any more.
+	 */
+	if (!ssi_private->imx_ac97) {
+		write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+				CCSR_SSI_SxCCR_DC(2));
+		write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+				CCSR_SSI_SxCCR_DC(2));
+	}
+
 	return 0;
 }
 
-- 
1.8.4

^ permalink raw reply related

* [PATCH v2] ASoC: fsl_esai: Add ESAI CPU DAI driver
From: Nicolin Chen @ 2014-01-09 10:57 UTC (permalink / raw)
  To: broonie, timur, alsa-devel
  Cc: mark.rutland, devicetree, pawel.moll, ijc+devicetree, tiwai,
	linux-kernel, linux-doc, lgirdwood, perex, robh+dt, rob, galak,
	grant.likely, shawn.guo, linuxppc-dev

This patch implements a device-tree-only CPU DAI driver for Freescale ESAI
controller that supports:

 - 12 channels playback and 8 channels record.
   [ Some of the inner transmitters and receivers are sharing same group of
     pins. So the maxmium 12 output or 8 input channels are only valid if
     there is no pin conflict occurring to it. ]

 - Independent (asynchronous mode) or shared (synchronous mode) transmit and
   receive sections with separate or shared internal/external clocks and frame
   syncs, operating in Master or Slave mode.
   [ Current ALSA seems not to allow CPU DAI drivers to set DAI format and clks
     separately for PLAYBACK and CAPTURE. So this first version only supports
     the case that uses the same DAI format for both directions. ]

 - Various DAI formats: I2S, Left-Justified, Right-Justified, DSP-A and DSP-B.

 - Programmable word length (8, 16, 20 or 24bits)

 - Flexible selection between system clock or external oscillator as input
   clock source, programmable internal clock divider and frame sync generation.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---

Changelog
v2:
 * Correct multi-line comments.
 * Add missing spaces between number and operator.

 .../devicetree/bindings/sound/fsl,esai.txt         |  54 ++
 sound/soc/fsl/Kconfig                              |   3 +
 sound/soc/fsl/Makefile                             |   2 +
 sound/soc/fsl/fsl_esai.c                           | 815 +++++++++++++++++++++
 sound/soc/fsl/fsl_esai.h                           | 352 +++++++++
 5 files changed, 1226 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,esai.txt
 create mode 100644 sound/soc/fsl/fsl_esai.c
 create mode 100644 sound/soc/fsl/fsl_esai.h

diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
new file mode 100644
index 0000000..4372833
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -0,0 +1,54 @@
+Freescale Enhanced Serial Audio Interface (ESAI) Controller
+
+The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
+for serial communication with a variety of serial devices, including industry
+standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
+other DSPs. It has up to six transmitters and four receivers.
+
+Required properties:
+
+  - compatible : Compatible list, must contain "fsl,imx35-esai".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks: Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"core"		The core clock used to access registers
+	"extal"		The esai baud clock for esai controller used to derive
+			HCK, SCK and FS.
+	"fsys"		The system clock derived from ahb clock used to derive
+			HCK, SCK and FS.
+
+  - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
+    This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
+
+  - fsl,esai-synchronous: This is a boolean property. If present, indicating
+    that ESAI would work in the synchronous mode, which means all the settings
+    for Receiving would be duplicated from Transmition related registers.
+
+  - fsl,esai-network-mode: This is a boolean property. If present, indicating
+    that ESAI controller would work in its network mode.
+
+Example:
+
+esai: esai@02024000 {
+	compatible = "fsl,imx35-esai";
+	reg = <0x02024000 0x4000>;
+	interrupts = <0 51 0x04>;
+	clocks = <&clks 208>, <&clks 118>, <&clks 208>;
+	clock-names = "core", "extal", "fsys";
+	dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
+	dma-names = "rx", "tx";
+	fsl,fifo-depth = <128>;
+	fsl,esai-synchronous;
+	fsl,esai-network-mode;
+	status = "disabled";
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 514c275..324988d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -8,6 +8,9 @@ config SND_SOC_FSL_SSI
 config SND_SOC_FSL_SPDIF
 	tristate
 
+config SND_SOC_FSL_ESAI
+	tristate
+
 config SND_SOC_FSL_UTILS
 	tristate
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index aaccbee..b12ad4b 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -14,11 +14,13 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 snd-soc-fsl-sai-objs := fsl_sai.o
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-spdif-objs := fsl_spdif.o
+snd-soc-fsl-esai-objs := fsl_esai.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
 obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
+obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644
index 0000000..a30b1fd
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.c
@@ -0,0 +1,815 @@
+/*
+ * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_esai.h"
+#include "imx-pcm.h"
+
+#define FSL_ESAI_RATES		SNDRV_PCM_RATE_8000_192000
+#define FSL_ESAI_FORMATS	(SNDRV_PCM_FMTBIT_S8 | \
+				SNDRV_PCM_FMTBIT_S16_LE | \
+				SNDRV_PCM_FMTBIT_S20_3LE | \
+				SNDRV_PCM_FMTBIT_S24_LE)
+
+/**
+ * fsl_esai: ESAI private data
+ *
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @coreclk: clock source to access register
+ * @extalclk: esai clock source to derive HCK, SCK and FS
+ * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @fifo_depth: depth of tx/rx FIFO
+ * @sck_div: if using PSR/PM dividers for SCK clock
+ * @network_mode: if using network mode
+ * @synchronous: if using tx/rx synchronous mode
+ * @name: driver name
+ */
+struct fsl_esai {
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	struct clk *coreclk;
+	struct clk *extalclk;
+	struct clk *fsysclk;
+	u32 fifo_depth;
+	u32 slot_width;
+	bool sck_div;
+	bool network_mode;
+	bool synchronous;
+	char name[32];
+};
+
+static irqreturn_t esai_isr(int irq, void *devid)
+{
+	struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
+	struct platform_device *pdev = esai_priv->pdev;
+	u32 esr;
+
+	regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
+
+	if (esr & ESAI_ESR_TINIT_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
+
+	if (esr & ESAI_ESR_RFF_MASK)
+		dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+
+	if (esr & ESAI_ESR_TFE_MASK)
+		dev_warn(&pdev->dev, "isr: Transmition underrun\n");
+
+	if (esr & ESAI_ESR_TLS_MASK)
+		dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
+
+	if (esr & ESAI_ESR_TDE_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
+
+	if (esr & ESAI_ESR_TED_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
+
+	if (esr & ESAI_ESR_TD_MASK)
+		dev_dbg(&pdev->dev, "isr: Transmitting data\n");
+
+	if (esr & ESAI_ESR_RLS_MASK)
+		dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
+
+	if (esr & ESAI_ESR_RDE_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
+
+	if (esr & ESAI_ESR_RED_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
+
+	if (esr & ESAI_ESR_RD_MASK)
+		dev_dbg(&pdev->dev, "isr: Receiving data\n");
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * This function is used to calculate the divisors of psr, pm, fp and it is
+ * supposed to be called in set_dai_sysclk() and set_bclk_ratio().
+ *
+ * @ratio: desired overall ratio for the paticipating dividers
+ * @usefp: for HCK setting, there is no need to set fp divider
+ * @fp: bypass other dividers by setting fp directly if fp != 0
+ */
+static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, u32 ratio,
+				bool usefp, u32 fp)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
+
+	maxfp = usefp ? 16 : 1;
+
+	if (usefp && fp)
+		goto out_fp;
+
+	if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
+		dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
+				2 * 8 * 256 * maxfp);
+		return -EINVAL;
+	} else if (ratio % 2) {
+		dev_err(dai->dev, "the raio must be even if using upper divider\n");
+		return -EINVAL;
+	}
+
+	ratio /= 2;
+
+	psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
+
+	/* Set the max fluctuation -- 0.1% of the max devisor */
+	savesub = (psr ? 1 : 8)  * 256 * maxfp / 1000;
+
+	/* Find the best value for PM */
+	for (i = 1; i <= 256; i++) {
+		for (j = 1; j <= maxfp; j++) {
+			/* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
+			prod = (psr ? 1 : 8) * i * j;
+
+			if (prod == ratio)
+				sub = 0;
+			else if (prod / ratio == 1)
+				sub = prod - ratio;
+			else if (ratio / prod == 1)
+				sub = ratio - prod;
+			else
+				continue;
+
+			/* Calculate the fraction */
+			sub = sub * 1000 / ratio;
+			if (sub < savesub) {
+				savesub = sub;
+				pm = i;
+				fp = j;
+			}
+
+			/* We are lucky */
+			if (savesub == 0)
+				goto out;
+		}
+	}
+
+	if (pm == 999) {
+		dev_err(dai->dev, "failed to calculate proper divisors\n");
+		return -EINVAL;
+	}
+
+out:
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+			   psr | ESAI_xCCR_xPM(pm));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+			   psr | ESAI_xCCR_xPM(pm));
+
+out_fp:
+	/* Bypass fp if not being required */
+	if (maxfp <= 1)
+		return 0;
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+
+	return 0;
+}
+
+/**
+ * This function mainly configures the clock frequency of MCLK (HCK)
+ *
+ * @Parameters:
+ * clk_id: The clock source of HCK
+ *	  (Input from outside; output from inside, FSYS or EXTAL)
+ * freq: The required clock rate of HCK
+ * dir: The clock direction of HCK
+ *
+ * Note: If the direction is input, we do not care about clk_id.
+ */
+static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+				   unsigned int freq, int dir)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool in = dir == SND_SOC_CLOCK_IN;
+	u32 ret, ratio, ecr = 0;
+	unsigned long clk_rate;
+
+	/* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
+	esai_priv->sck_div = true;
+
+	/* Set the direction of HCK pins */
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
+
+	if (in)
+		goto out;
+
+	switch (clk_id) {
+	case ESAI_HCK_FSYS:
+		if (IS_ERR(esai_priv->fsysclk)) {
+			dev_err(dai->dev, "no assigned fsys clock\n");
+			return -EINVAL;
+		}
+		clk_rate = clk_get_rate(esai_priv->fsysclk);
+		break;
+	case ESAI_HCK_EXTAL:
+		if (IS_ERR(esai_priv->extalclk)) {
+			dev_err(dai->dev, "no assigned extal clock\n");
+			return -EINVAL;
+		}
+		clk_rate = clk_get_rate(esai_priv->extalclk);
+
+		ecr |= ESAI_ECR_ETI | ESAI_ECR_ERI;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ratio = clk_rate / freq;
+	if (ratio * freq > clk_rate)
+		ret = ratio * freq - clk_rate;
+	else if (ratio * freq < clk_rate)
+		ret = clk_rate - ratio * freq;
+	else
+		ret = 0;
+
+	/* Block if clock source can not be divided into the required rate */
+	if (ret != 0 && clk_rate / ret < 1000) {
+		dev_err(dai->dev, "failed to derive the required frequency\n");
+		return -EINVAL;
+	}
+
+	if (ratio == 1) {
+		/* Bypass all the dividers if not being needed */
+		ecr |= ESAI_ECR_ETO | ESAI_ECR_ERO;
+		goto out;
+	}
+
+	ret = fsl_esai_divisor_cal(dai, ratio, false, 0);
+	if (ret)
+		return ret;
+
+	esai_priv->sck_div = false;
+
+out:
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
+			   ESAI_ECR_ETI | ESAI_ECR_ETO |
+			   ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
+
+	return 0;
+}
+
+/**
+ * This function configures the ratio between MCLK (HCK) and BCLK (SCK)
+ * (For DAI Master Mode only)
+ *
+ * Note: Machine driver should calculate the ratio to call this function.
+ * 	 Only effective after calling set_dai_sysclk() to set HCK direction.
+ */
+static int fsl_esai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 fp = esai_priv->sck_div ? 0 : ratio;
+
+	if (!esai_priv->sck_div && (ratio > 16 || ratio == 0)) {
+		dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
+		return -EINVAL;
+	}
+
+	return fsl_esai_divisor_cal(dai, ratio, true, fp);
+}
+
+/**
+ * This function provides a manual way to configure all the dividers directly
+ * (For DAI Master Mode only)
+ *
+ * By using this function, the driver would allow user to configure a flexible
+ * combination of divisors for both TX and RX route separately
+ *
+ * Note: Only effective after calling set_dai_sysclk() to set HCK direction
+ */
+static int fsl_esai_set_dai_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = div_id <= ESAI_TX_DIV_FP;
+	u32 mask, val;
+
+	switch (div_id) {
+	case ESAI_TX_DIV_PSR:
+	case ESAI_RX_DIV_PSR:
+		mask = ESAI_xCCR_xPSR_MASK;
+		val = div ? ESAI_xCCR_xPSR_BYPASS : 0;
+		break;
+	case ESAI_TX_DIV_PM:
+	case ESAI_RX_DIV_PM:
+		mask = ESAI_xCCR_xPM_MASK;
+		val = ESAI_xCCR_xPM(div);
+		break;
+	case ESAI_TX_DIV_FP:
+	case ESAI_RX_DIV_FP:
+		mask = ESAI_xCCR_xFP_MASK;
+		val = ESAI_xCCR_xFP(div);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx), mask, val);
+}
+
+static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
+				     u32 rx_mask, int slots, int slot_width)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+			   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+			   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
+			   ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+
+	esai_priv->slot_width = slot_width;
+
+	return 0;
+}
+
+static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	u32 xcr = 0, xccr = 0, mask;
+
+	/* DAI mode */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		/* Data on rising edge of bclk, frame low, 1clk before data */
+		xcr |= ESAI_xCR_xFSR;
+		xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		/* Data on rising edge of bclk, frame high */
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		/* Data on rising edge of bclk, frame high, right aligned */
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* Data on rising edge of bclk, frame high, 1clk before data */
+		xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		/* Data on rising edge of bclk, frame high */
+		xcr |= ESAI_xCR_xFSL;
+		xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* Nothing to do for both normal cases */
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		/* Invert bit clock */
+		xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		/* Invert frame clock */
+		xccr ^= ESAI_xCCR_xFSP;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Invert both clocks */
+		xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* DAI clock master masks */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		xccr |= ESAI_xCCR_xCKD;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		xccr |= ESAI_xCCR_xFSD;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
+
+	mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
+		ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
+
+	return 0;
+}
+
+static int fsl_esai_startup(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	/*
+	 * Some platforms might use the same bit to gate all three or two of
+	 * clocks, so keep all clocks open/close at the same time for safety
+	 */
+	clk_prepare_enable(esai_priv->coreclk);
+	if (!IS_ERR(esai_priv->extalclk))
+		clk_prepare_enable(esai_priv->extalclk);
+	if (!IS_ERR(esai_priv->fsysclk))
+		clk_prepare_enable(esai_priv->fsysclk);
+
+	if (!dai->active) {
+		/* Reset Port C */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
+				   ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
+				   ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
+
+		/* Set synchronous mode */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
+				   ESAI_SAICR_SYNC, esai_priv->synchronous ?
+				   ESAI_SAICR_SYNC : 0);
+
+		/* Set network mode */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
+				   ESAI_xCR_xMOD_MASK, esai_priv->network_mode ?
+				   ESAI_xCR_xMOD_NETWORK : 0);
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
+				   ESAI_xCR_xMOD_MASK, esai_priv->network_mode ?
+				   ESAI_xCR_xMOD_NETWORK : 0);
+
+		/* Set a default slot number -- 2 */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+				   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+				   ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+	}
+
+	return 0;
+}
+
+static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u32 width = snd_pcm_format_width(params_format(params));
+	u32 channels = params_channels(params);
+	u32 mask, val;
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+			   ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
+
+	mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
+	      (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
+	val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth / 2) |
+	     (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
+
+	mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
+	val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+
+	regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+
+	return 0;
+}
+
+static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	if (!IS_ERR(esai_priv->fsysclk))
+		clk_disable_unprepare(esai_priv->fsysclk);
+	if (!IS_ERR(esai_priv->extalclk))
+		clk_disable_unprepare(esai_priv->extalclk);
+	clk_disable_unprepare(esai_priv->coreclk);
+}
+
+static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	u8 i, channels = substream->runtime->channels;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
+
+		/* Write initial words reqiured by ESAI as normal procedure */
+		for (i = 0; tx && i < channels; i++)
+			regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
+
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+				   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
+				   tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+				   tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
+
+		/* Disable and reset FIFO */
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
+		regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+				   ESAI_xFCR_xFR, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+	.startup = fsl_esai_startup,
+	.shutdown = fsl_esai_shutdown,
+	.trigger = fsl_esai_trigger,
+	.hw_params = fsl_esai_hw_params,
+	.set_sysclk = fsl_esai_set_dai_sysclk,
+	.set_bclk_ratio = fsl_esai_set_bclk_ratio,
+	.set_clkdiv = fsl_esai_set_dai_clkdiv,
+	.set_fmt = fsl_esai_set_dai_fmt,
+	.set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
+static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+	snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
+				  &esai_priv->dma_params_rx);
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+	.probe = fsl_esai_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 12,
+		.rates = FSL_ESAI_RATES,
+		.formats = FSL_ESAI_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = FSL_ESAI_RATES,
+		.formats = FSL_ESAI_FORMATS,
+	},
+	.ops = &fsl_esai_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_esai_component = {
+	.name		= "fsl-esai",
+};
+
+static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_ESAI_ERDR:
+	case REG_ESAI_ECR:
+	case REG_ESAI_ESR:
+	case REG_ESAI_TFCR:
+	case REG_ESAI_TFSR:
+	case REG_ESAI_RFCR:
+	case REG_ESAI_RFSR:
+	case REG_ESAI_RX0:
+	case REG_ESAI_RX1:
+	case REG_ESAI_RX2:
+	case REG_ESAI_RX3:
+	case REG_ESAI_SAISR:
+	case REG_ESAI_SAICR:
+	case REG_ESAI_TCR:
+	case REG_ESAI_TCCR:
+	case REG_ESAI_RCR:
+	case REG_ESAI_RCCR:
+	case REG_ESAI_TSMA:
+	case REG_ESAI_TSMB:
+	case REG_ESAI_RSMA:
+	case REG_ESAI_RSMB:
+	case REG_ESAI_PRRC:
+	case REG_ESAI_PCRC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_ESAI_ETDR:
+	case REG_ESAI_ECR:
+	case REG_ESAI_TFCR:
+	case REG_ESAI_RFCR:
+	case REG_ESAI_TX0:
+	case REG_ESAI_TX1:
+	case REG_ESAI_TX2:
+	case REG_ESAI_TX3:
+	case REG_ESAI_TX4:
+	case REG_ESAI_TX5:
+	case REG_ESAI_TSR:
+	case REG_ESAI_SAICR:
+	case REG_ESAI_TCR:
+	case REG_ESAI_TCCR:
+	case REG_ESAI_RCR:
+	case REG_ESAI_RCCR:
+	case REG_ESAI_TSMA:
+	case REG_ESAI_TSMB:
+	case REG_ESAI_RSMA:
+	case REG_ESAI_RSMB:
+	case REG_ESAI_PRRC:
+	case REG_ESAI_PCRC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config fsl_esai_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = REG_ESAI_PCRC,
+	.readable_reg = fsl_esai_readable_reg,
+	.writeable_reg = fsl_esai_writeable_reg,
+};
+
+static int fsl_esai_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_esai *esai_priv;
+	struct resource *res;
+	const uint32_t *iprop;
+	void __iomem *regs;
+	int irq, ret;
+
+	esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
+	if (!esai_priv)
+		return -ENOMEM;
+
+	esai_priv->pdev = pdev;
+	strcpy(esai_priv->name, np->name);
+
+	/* Get the addresses and IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+			"core", regs, &fsl_esai_regmap_config);
+	if (IS_ERR(esai_priv->regmap)) {
+		dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+				PTR_ERR(esai_priv->regmap));
+		return PTR_ERR(esai_priv->regmap);
+	}
+
+	esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+	if (IS_ERR(esai_priv->coreclk)) {
+		dev_err(&pdev->dev, "failed to get core clock: %ld\n",
+				PTR_ERR(esai_priv->coreclk));
+		return PTR_ERR(esai_priv->coreclk);
+	}
+
+	esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
+	if (IS_ERR(esai_priv->extalclk))
+		dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
+				PTR_ERR(esai_priv->extalclk));
+
+	esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
+	if (IS_ERR(esai_priv->fsysclk))
+		dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
+				PTR_ERR(esai_priv->fsysclk));
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
+			       esai_priv->name, esai_priv);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+		return ret;
+	}
+
+	/* Set a default slot size */
+	esai_priv->slot_width = 32;
+
+	/* Determine the FIFO depth */
+	iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+	if (iprop)
+		esai_priv->fifo_depth = be32_to_cpup(iprop);
+	else
+		esai_priv->fifo_depth = 64;
+
+	esai_priv->dma_params_tx.maxburst = esai_priv->fifo_depth > 1;
+	esai_priv->dma_params_rx.maxburst = esai_priv->fifo_depth > 1;
+	esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
+	esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
+
+	esai_priv->synchronous =
+		of_property_read_bool(np, "fsl,esai-synchronous");
+	esai_priv->network_mode =
+		of_property_read_bool(np, "fsl,esai-network-mode");
+
+	dev_set_drvdata(&pdev->dev, esai_priv);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
+					      &fsl_esai_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+		return ret;
+	}
+
+	ret = imx_pcm_dma_init(pdev);
+	if (ret)
+		dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+	/* Reset ESAI unit */
+	regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
+
+	/*
+	 * We need to enable ESAI so as to access some of its registers.
+	 * Otherwise, we would fail to dump regmap from user space.
+	 */
+	regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
+
+	return ret;
+}
+
+static const struct of_device_id fsl_esai_dt_ids[] = {
+	{ .compatible = "fsl,imx35-esai", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
+
+static struct platform_driver fsl_esai_driver = {
+	.probe = fsl_esai_probe,
+	.driver = {
+		.name = "fsl-esai-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_esai_dt_ids,
+	},
+};
+
+module_platform_driver(fsl_esai_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-esai-dai");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644
index 0000000..680aac0
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.h
@@ -0,0 +1,352 @@
+/*
+ * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_ESAI_DAI_H
+#define _FSL_ESAI_DAI_H
+
+/* ESAI Register Map */
+#define REG_ESAI_ETDR		0x00
+#define REG_ESAI_ERDR		0x04
+#define REG_ESAI_ECR		0x08
+#define REG_ESAI_ESR		0x0C
+#define REG_ESAI_TFCR		0x10
+#define REG_ESAI_TFSR		0x14
+#define REG_ESAI_RFCR		0x18
+#define REG_ESAI_RFSR		0x1C
+#define REG_ESAI_xFCR(tx)	(tx ? REG_ESAI_TFCR : REG_ESAI_RFCR)
+#define REG_ESAI_xFSR(tx)	(tx ? REG_ESAI_TFSR : REG_ESAI_RFSR)
+#define REG_ESAI_TX0		0x80
+#define REG_ESAI_TX1		0x84
+#define REG_ESAI_TX2		0x88
+#define REG_ESAI_TX3		0x8C
+#define REG_ESAI_TX4		0x90
+#define REG_ESAI_TX5		0x94
+#define REG_ESAI_TSR		0x98
+#define REG_ESAI_RX0		0xA0
+#define REG_ESAI_RX1		0xA4
+#define REG_ESAI_RX2		0xA8
+#define REG_ESAI_RX3		0xAC
+#define REG_ESAI_SAISR		0xCC
+#define REG_ESAI_SAICR		0xD0
+#define REG_ESAI_TCR		0xD4
+#define REG_ESAI_TCCR		0xD8
+#define REG_ESAI_RCR		0xDC
+#define REG_ESAI_RCCR		0xE0
+#define REG_ESAI_xCR(tx)	(tx ? REG_ESAI_TCR : REG_ESAI_RCR)
+#define REG_ESAI_xCCR(tx)	(tx ? REG_ESAI_TCCR : REG_ESAI_RCCR)
+#define REG_ESAI_TSMA		0xE4
+#define REG_ESAI_TSMB		0xE8
+#define REG_ESAI_RSMA		0xEC
+#define REG_ESAI_RSMB		0xF0
+#define REG_ESAI_xSMA(tx)	(tx ? REG_ESAI_TSMA : REG_ESAI_RSMA)
+#define REG_ESAI_xSMB(tx)	(tx ? REG_ESAI_TSMB : REG_ESAI_RSMB)
+#define REG_ESAI_PRRC		0xF8
+#define REG_ESAI_PCRC		0xFC
+
+/* ESAI Control Register -- REG_ESAI_ECR 0x8 */
+#define ESAI_ECR_ETI_SHIFT	19
+#define ESAI_ECR_ETI_MASK	(1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETI		(1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETO_SHIFT	18
+#define ESAI_ECR_ETO_MASK	(1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ETO		(1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ERI_SHIFT	17
+#define ESAI_ECR_ERI_MASK	(1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERI		(1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERO_SHIFT	16
+#define ESAI_ECR_ERO_MASK	(1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERO		(1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERST_SHIFT	1
+#define ESAI_ECR_ERST_MASK	(1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ERST		(1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ESAIEN_SHIFT	0
+#define ESAI_ECR_ESAIEN_MASK	(1 << ESAI_ECR_ESAIEN_SHIFT)
+#define ESAI_ECR_ESAIEN		(1 << ESAI_ECR_ESAIEN_SHIFT)
+
+/* ESAI Status Register -- REG_ESAI_ESR 0xC */
+#define ESAI_ESR_TINIT_SHIFT	10
+#define ESAI_ESR_TINIT_MASK	(1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_TINIT		(1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_RFF_SHIFT	9
+#define ESAI_ESR_RFF_MASK	(1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_RFF		(1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_TFE_SHIFT	8
+#define ESAI_ESR_TFE_MASK	(1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TFE		(1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TLS_SHIFT	7
+#define ESAI_ESR_TLS_MASK	(1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TLS		(1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TDE_SHIFT	6
+#define ESAI_ESR_TDE_MASK	(1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TDE		(1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TED_SHIFT	5
+#define ESAI_ESR_TED_MASK	(1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TED		(1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TD_SHIFT	4
+#define ESAI_ESR_TD_MASK	(1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_TD		(1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_RLS_SHIFT	3
+#define ESAI_ESR_RLS_MASK	(1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RLS		(1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RDE_SHIFT	2
+#define ESAI_ESR_RDE_MASK	(1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RDE		(1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RED_SHIFT	1
+#define ESAI_ESR_RED_MASK	(1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RED		(1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RD_SHIFT	0
+#define ESAI_ESR_RD_MASK	(1 << ESAI_ESR_RD_SHIFT)
+#define ESAI_ESR_RD		(1 << ESAI_ESR_RD_SHIFT)
+
+/*
+ * Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10
+ * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18
+ */
+#define ESAI_xFCR_TIEN_SHIFT	19
+#define ESAI_xFCR_TIEN_MASK	(1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_TIEN		(1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_REXT_SHIFT	19
+#define ESAI_xFCR_REXT_MASK	(1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_REXT		(1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_xWA_SHIFT	16
+#define ESAI_xFCR_xWA_WIDTH	3
+#define ESAI_xFCR_xWA_MASK	(((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT)
+#define ESAI_xFCR_xWA(v)	(((8 - (v >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK)
+#define ESAI_xFCR_xFWM_SHIFT	8
+#define ESAI_xFCR_xFWM_WIDTH	8
+#define ESAI_xFCR_xFWM_MASK	(((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT)
+#define ESAI_xFCR_xFWM(v)	(((v - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK)
+#define ESAI_xFCR_xE_SHIFT	2
+#define ESAI_xFCR_TE_WIDTH	6
+#define ESAI_xFCR_RE_WIDTH	4
+#define ESAI_xFCR_TE_MASK	(((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_RE_MASK	(((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_TE(x) 	((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x) 	((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_xFR_SHIFT	1
+#define ESAI_xFCR_xFR_MASK	(1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFR		(1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFEN_SHIFT	0
+#define ESAI_xFCR_xFEN_MASK	(1 << ESAI_xFCR_xFEN_SHIFT)
+#define ESAI_xFCR_xFEN		(1 << ESAI_xFCR_xFEN_SHIFT)
+
+/*
+ * Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14
+ * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C
+ */
+#define ESAI_xFSR_NTFO_SHIFT	12
+#define ESAI_xFSR_NRFI_SHIFT	12
+#define ESAI_xFSR_NTFI_SHIFT	8
+#define ESAI_xFSR_NRFO_SHIFT	8
+#define ESAI_xFSR_NTFx_WIDTH	3
+#define ESAI_xFSR_NRFx_WIDTH	2
+#define ESAI_xFSR_NTFO_MASK	(((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT)
+#define ESAI_xFSR_NTFI_MASK	(((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT)
+#define ESAI_xFSR_NRFO_MASK	(((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT)
+#define ESAI_xFSR_NRFI_MASK	(((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT)
+#define ESAI_xFSR_xFCNT_SHIFT	0
+#define ESAI_xFSR_xFCNT_WIDTH	8
+#define ESAI_xFSR_xFCNT_MASK	(((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT)
+
+/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */
+#define ESAI_TSR_SHIFT		0
+#define ESAI_TSR_WIDTH		24
+#define ESAI_TSR_MASK		(((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT)
+
+/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */
+#define ESAI_SAISR_TODFE_SHIFT	17
+#define ESAI_SAISR_TODFE_MASK	(1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TODFE	(1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TEDE_SHIFT	16
+#define ESAI_SAISR_TEDE_MASK	(1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TEDE		(1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TDE_SHIFT	15
+#define ESAI_SAISR_TDE_MASK	(1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TDE		(1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TUE_SHIFT	14
+#define ESAI_SAISR_TUE_MASK	(1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TUE		(1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TFS_SHIFT	13
+#define ESAI_SAISR_TFS_MASK	(1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_TFS		(1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_RODF_SHIFT	10
+#define ESAI_SAISR_RODF_MASK	(1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_RODF		(1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_REDF_SHIFT	9
+#define ESAI_SAISR_REDF_MASK	(1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_REDF		(1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_RDF_SHIFT	8
+#define ESAI_SAISR_RDF_MASK	(1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_RDF		(1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_ROE_SHIFT	7
+#define ESAI_SAISR_ROE_MASK	(1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_ROE		(1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_RFS_SHIFT	6
+#define ESAI_SAISR_RFS_MASK	(1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_RFS		(1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_IF2_SHIFT	2
+#define ESAI_SAISR_IF2_MASK	(1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF2		(1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF1_SHIFT	1
+#define ESAI_SAISR_IF1_MASK	(1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF1		(1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF0_SHIFT	0
+#define ESAI_SAISR_IF0_MASK	(1 << ESAI_SAISR_IF0_SHIFT)
+#define ESAI_SAISR_IF0		(1 << ESAI_SAISR_IF0_SHIFT)
+
+/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */
+#define ESAI_SAICR_ALC_SHIFT	8
+#define ESAI_SAICR_ALC_MASK	(1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_ALC		(1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_TEBE_SHIFT	7
+#define ESAI_SAICR_TEBE_MASK	(1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_TEBE		(1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_SYNC_SHIFT	6
+#define ESAI_SAICR_SYNC_MASK	(1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_SYNC		(1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_OF2_SHIFT	2
+#define ESAI_SAICR_OF2_MASK	(1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF2		(1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF1_SHIFT	1
+#define ESAI_SAICR_OF1_MASK	(1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF1		(1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF0_SHIFT	0
+#define ESAI_SAICR_OF0_MASK	(1 << ESAI_SAICR_OF0_SHIFT)
+#define ESAI_SAICR_OF0		(1 << ESAI_SAICR_OF0_SHIFT)
+
+/*
+ * Transmit Control Register -- REG_ESAI_TCR 0xD4
+ * Receive Control Register -- REG_ESAI_RCR 0xDC
+ */
+#define ESAI_xCR_xLIE_SHIFT	23
+#define ESAI_xCR_xLIE_MASK	(1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xLIE		(1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xIE_SHIFT	22
+#define ESAI_xCR_xIE_MASK	(1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xIE		(1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xEDIE_SHIFT	21
+#define ESAI_xCR_xEDIE_MASK	(1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEDIE		(1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEIE_SHIFT	20
+#define ESAI_xCR_xEIE_MASK	(1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xEIE		(1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xPR_SHIFT	19
+#define ESAI_xCR_xPR_MASK	(1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_xPR		(1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_PADC_SHIFT	17
+#define ESAI_xCR_PADC_MASK	(1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_PADC		(1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_xFSR_SHIFT	16
+#define ESAI_xCR_xFSR_MASK	(1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSR		(1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSL_SHIFT	15
+#define ESAI_xCR_xFSL_MASK	(1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xFSL		(1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xSWS_SHIFT	10
+#define ESAI_xCR_xSWS_WIDTH	5
+#define ESAI_xCR_xSWS_MASK	(((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xSWS(s, w)	((w < 24 ? (s - w + ((w - 8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xMOD_SHIFT	8
+#define ESAI_xCR_xMOD_WIDTH	2
+#define ESAI_xCR_xMOD_MASK	(((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_ONDEMAND	(0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_NETWORK	(0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_AC97	(0x3 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xWA_SHIFT	7
+#define ESAI_xCR_xWA_MASK	(1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xWA		(1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xSHFD_SHIFT	6
+#define ESAI_xCR_xSHFD_MASK	(1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xSHFD		(1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xE_SHIFT	0
+#define ESAI_xCR_TE_WIDTH	6
+#define ESAI_xCR_RE_WIDTH	4
+#define ESAI_xCR_TE_MASK	(((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_RE_MASK	(((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_TE(x) 		((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x) 		((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+
+/*
+ * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
+ * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0
+ */
+#define ESAI_xCCR_xHCKD_SHIFT	23
+#define ESAI_xCCR_xHCKD_MASK	(1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xHCKD		(1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xFSD_SHIFT	22
+#define ESAI_xCCR_xFSD_MASK	(1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xFSD		(1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xCKD_SHIFT	21
+#define ESAI_xCCR_xCKD_MASK	(1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xCKD		(1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xHCKP_SHIFT	20
+#define ESAI_xCCR_xHCKP_MASK	(1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xHCKP		(1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xFSP_SHIFT	19
+#define ESAI_xCCR_xFSP_MASK	(1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xFSP		(1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xCKP_SHIFT	18
+#define ESAI_xCCR_xCKP_MASK	(1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xCKP		(1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xFP_SHIFT	14
+#define ESAI_xCCR_xFP_WIDTH	4
+#define ESAI_xCCR_xFP_MASK	(((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
+#define ESAI_xCCR_xFP(v)	(((v - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
+#define ESAI_xCCR_xDC_SHIFT     9
+#define ESAI_xCCR_xDC_WIDTH	4
+#define ESAI_xCCR_xDC_MASK	(((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
+#define ESAI_xCCR_xDC(v)	(((v - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
+#define ESAI_xCCR_xPSR_SHIFT	8
+#define ESAI_xCCR_xPSR_MASK	(1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_BYPASS	(1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_DIV8	(0 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPM_SHIFT     0
+#define ESAI_xCCR_xPM_WIDTH     8
+#define ESAI_xCCR_xPM_MASK	(((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT)
+#define ESAI_xCCR_xPM(v)	(((v - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK)
+
+/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 ~ 0xF0 */
+#define ESAI_xSMA_xS_SHIFT	0
+#define ESAI_xSMA_xS_WIDTH	16
+#define ESAI_xSMA_xS_MASK	(((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT)
+#define ESAI_xSMA_xS(v)		(v & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS_SHIFT	0
+#define ESAI_xSMB_xS_WIDTH	16
+#define ESAI_xSMB_xS_MASK	(((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
+#define ESAI_xSMB_xS(v)		((v >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+
+/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
+#define ESAI_PRRC_PDC_SHIFT	0
+#define ESAI_PRRC_PDC_WIDTH	12
+#define ESAI_PRRC_PDC_MASK	(((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT)
+#define ESAI_PRRC_PDC(v)	(v & ESAI_PRRC_PDC_MASK)
+
+/* Port C Control Register -- REG_ESAI_PCRC 0xFC */
+#define ESAI_PCRC_PC_SHIFT	0
+#define ESAI_PCRC_PC_WIDTH	12
+#define ESAI_PCRC_PC_MASK	(((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT)
+#define ESAI_PCRC_PC(v)		(v & ESAI_PCRC_PC_MASK)
+
+#define ESAI_GPIO		0xfff
+
+/* ESAI clock source */
+#define ESAI_HCK_FSYS		0
+#define ESAI_HCK_EXTAL		1
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR		0
+#define ESAI_TX_DIV_PM		1
+#define ESAI_TX_DIV_FP		2
+#define ESAI_RX_DIV_PSR		3
+#define ESAI_RX_DIV_PM		4
+#define ESAI_RX_DIV_FP		5
+#endif /* _FSL_ESAI_DAI_H */
-- 
1.8.4

^ permalink raw reply related

* Re: [PATCH 0/4] powernv: kvm: numa fault improvement
From: Alexander Graf @ 2014-01-09 12:08 UTC (permalink / raw)
  To: Liu Ping Fan; +Cc: Paul Mackerras, linuxppc-dev, Aneesh Kumar K.V, kvm-ppc
In-Reply-To: <1386751674-14136-1-git-send-email-pingfank@linux.vnet.ibm.com>


On 11.12.2013, at 09:47, Liu Ping Fan <kernelfans@gmail.com> wrote:

> This series is based on Aneesh's series  "[PATCH -V2 0/5] powerpc: mm: =
Numa faults support for ppc64"
>=20
> For this series, I apply the same idea from the previous thread =
"[PATCH 0/3] optimize for powerpc _PAGE_NUMA"
> (for which, I still try to get a machine to show nums)
>=20
> But for this series, I think that I have a good justification -- the =
fact of heavy cost when switching context between guest and host,
> which is  well known.

This cover letter isn't really telling me anything. Please put a proper =
description of what you're trying to achieve, why you're trying to =
achieve what you're trying and convince your readers that it's a good =
idea to do it the way you do it.

> If my suppose is correct, will CCing kvm@vger.kernel.org from next =
version.

This translates to me as "This is an RFC"?


Alex

^ permalink raw reply

* Re: [PATCH RFC v6 4/5] dma: mpc512x: register for device tree channel lookup
From: Vinod Koul @ 2014-01-09 11:19 UTC (permalink / raw)
  To: Gerhard Sittig
  Cc: Lars-Peter Clausen, Arnd Bergmann, Alexander Popov, dmaengine,
	Dan Williams, Anatolij Gustschin, linuxppc-dev
In-Reply-To: <20140108164719.GO20094@book.gsilab.sittig.org>

On Wed, Jan 08, 2014 at 05:47:19PM +0100, Gerhard Sittig wrote:
> [ dropping devicetree from the Cc: list ]
> 
> [ what is the semantics of DMA_PRIVATE capability flag?
>   is documentation available beyond the initial commit message?
>   need individual channels be handled instead of controllers? ]

The DMA_PRIVATE means that your channels are not to be used for global memcpy,
as one can do in async cases (this is hwere DMAengine came into existence)

If the device has the capablity of doing genric memcpy then it should not set
this. For slave dma usage the dam channel can transfer data to a specfic
slave device(s), hence we should use this is geric fashion so setting
DMA_PRIVATE makes sense in those cases.

> 
> On Sat, Jan 04, 2014 at 00:54 +0400, Alexander Popov wrote:
> > 
> > Hello Gerhard.
> > Thanks for your review.
> > 
> > 2013/12/26 Gerhard Sittig <gsi@denx.de>:
> > > [ dropping devicetree, we're DMA specific here ]
> > >
> > > On Tue, Dec 24, 2013 at 16:06 +0400, Alexander Popov wrote:
> > >>
> > >> --- a/drivers/dma/mpc512x_dma.c
> > >> +++ b/drivers/dma/mpc512x_dma.c
> > >> [ ... ]
> > >> @@ -950,6 +951,7 @@ static int mpc_dma_probe(struct platform_device *op)
> > >>       INIT_LIST_HEAD(&dma->channels);
> > >>       dma_cap_set(DMA_MEMCPY, dma->cap_mask);
> > >>       dma_cap_set(DMA_SLAVE, dma->cap_mask);
> > >> +     dma_cap_set(DMA_PRIVATE, dma->cap_mask);
> > >>
> > >>       for (i = 0; i < dma->chancnt; i++) {
> > >>               mchan = &mdma->channels[i];
> > >
> > > What are the implications of this?  Is a comment due?
> > 
> > I've involved DMA_PRIVATE flag because new of_dma_xlate_by_chan_id()
> > uses dma_get_slave_channel() instead of dma_request_channel()
> > (PATCH RFC v6 3/5). This flag is implicitly set in dma_request_channel(),
> > but is not set in dma_get_slave_channel().
Which makes me thing you are targetting slave usages. Do you intend to use for
mempcy too on all controllers you support. in that case you should set it
selectively.

> > There are only two places in the mainline kernel, where
> > dma_get_slave_channel() is used. I've picked up the idea
> > at one of these places. Please look at this patch:
> > http://www.spinics.net/lists/arm-kernel/msg268718.html
> 
> I agree that the change looks simple, and there is no doubt that
> other drivers apply the flag.  None of this I questioned.  Yet
> I'm afraid that the implications are rather huge.
> 
> Unless I miss something, I'd happily learn where I'm wrong.
> 
> > > I haven't found documentation about the DMA_PRIVATE flag, only
> > > saw commit 59b5ec21446b9 "dmaengine: introduce
> > > dma_request_channel and private channels".
> > 
> > Unfortunately I didn't find any description of DMA_PRIVATE flag too.
> > But the comment at the beginning of drivers/dma/dmaengine.c
> > may give a clue. Quotation:
> >   * subsystem can get access to a channel by calling dmaengine_get() followed
> >   * by dma_find_channel(), or if it has need for an exclusive channel
> > it can call
> >   * dma_request_channel().  Once a channel is allocated a reference is taken
> >   * against its corresponding driver to disable removal.
> > 
> > DMA_PRIVATE capability flag might indicate that the DMA controller
> > can provide exclusive channels to its clients. Please correct me if I'm wrong.
> > 
> > > Alex, unless I'm
> > > missing something this one-line change is quite a change in
> > > semantics, and has dramatic influence on the code's behaviour
> > > (ignores the DMA controller when looking for channels that can do
> > > mem-to-mem transfers)
> > 
> > Excuse me, Gerhard, I don't see what you mean.
> > Could you point to the corresponding code?
> 
> You did see `git show 59b5ec21446b9`, didn't you?  The commit
> message strongly suggests that DMA_PRIVATE applies to the whole
> DMA controller and excludes _all_ of its channels from the
> general purpose allocator which mem-to-mem transfers appear to be
> using.  It's not just a hint, but an active decision to reject
> requests.
> 
> Not only checking code references, but doing a text search,
> reveals one more comment on the DMA_PRIVATE flag in a crypto
> related document, which supports my interpretation:
> Documentation/crypto/async-tx-api.txt:203
> 
> 
> Can somebody ACK or NAK my interpretation?  Dan, you committed
> this change which introduced the DMA_PRIVATE logic.  What was the
> motivation for it, or the goal to achieve?  Do other platforms
> have several dedicated DMA controllers, some for peripherals and
> some for memory transfers?  Should the "private" flag apply to
> channels and not whole controllers?  Am I over-estimating the
> benefit or importance of DMA supported memory transfers?

The DMA_PRIVATE flag is more on how the channel is allocated and will it be used
by generic allocator or not. You cna still use mecpy ops for a controller with
DMA_PRIVATE flag if the controller supports.
> 
> 
> Still I see a difference in the lookup approaches:  Yours applies
> DMA_PRIVATE globally and in advance, preventing _any_ use of DMA
> for memory transfers.  While the __dma_request_channel() routine
> only applies it _temporarily_ around a dma_chan_get() operation.
> Allowing for use of DMA channels by both individual peripherals
> as well as memory transfers.
> 
No it doesnt prevent. You can still use it for memcpy once you have the channel.

--
~Vinod
> 
> > > Consider the fact that this driver
> > > handles both MPC5121 as well as MPC8308 hardware.
> > 
> > Ah, yes, sorry. I should certainly fix this, if setting of DMA_PRIVATE flag
> > is needed at all.
> 
> What I meant here is that implications for all affected platforms
> should be considered.  There is one driver source, but the driver
> applies to more than one platform (another issue of the driver is
> that this is not apparent from the doc nor the compat strings).
> 
> MPC512x has one (GP) DMA controller, of which one channel is
> dedicated to DDR, and all other channels can get used for memory
> transfers as well.  In addition to most channels being connected
> to a specific peripheral for flow control.  Which your patch set
> introduces initial support for.
> 
> MPC8308 has _all_ channels for memory transfers exclusively (or
> at least none of its channels supports flow control).
> 
> So blocking memory transfers in mpc512x_dma.c is a total breakage
> for MPC8308 (removes the only previous feature and adds nothing),
> and is a regression for MPC512x (removes the previously supported
> memory transfers, while it may add peripheral supports with very
> few users).
> 
> 
> virtually yours
> Gerhard Sittig
> -- 
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de

-- 

^ permalink raw reply

* [PATCH -next] ASoC: fsl-ssi: Add missing clk_disable_unprepare() on error in fsl_ssi_probe()
From: Wei Yongjun @ 2014-01-09 14:27 UTC (permalink / raw)
  To: timur, lgirdwood, broonie, perex, tiwai, grant.likely, robh+dt
  Cc: yongjun_wei, linuxppc-dev, alsa-devel

From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>

Add the missing clk_disable_unprepare() before return from
fsl_ssi_probe() in the request irq error handling case.

Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
---
 sound/soc/fsl/fsl_ssi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index e18b4b3..4c6818d 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1464,7 +1464,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 		if (ret < 0) {
 			dev_err(&pdev->dev, "could not claim irq %u\n",
 					ssi_private->irq);
-			goto error_irqmap;
+			goto error_clk;
 		}
 	}
 

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox