18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/arch/arm/common/sa1111.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * SA1111 support
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Original code by John Dorsey
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file contains all generic SA1111 support.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * All initialization functions provided here are intended to be called
128c2ecf20Sopenharmony_ci * from machine specific code with proper arguments when required.
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/irq.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/delay.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci#include <linux/ioport.h>
228c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
258c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h>
268c2ecf20Sopenharmony_ci#include <linux/clk.h>
278c2ecf20Sopenharmony_ci#include <linux/io.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <mach/hardware.h>
308c2ecf20Sopenharmony_ci#include <asm/mach/irq.h>
318c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
328c2ecf20Sopenharmony_ci#include <linux/sizes.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <asm/hardware/sa1111.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* SA1111 IRQs */
378c2ecf20Sopenharmony_ci#define IRQ_GPAIN0		(0)
388c2ecf20Sopenharmony_ci#define IRQ_GPAIN1		(1)
398c2ecf20Sopenharmony_ci#define IRQ_GPAIN2		(2)
408c2ecf20Sopenharmony_ci#define IRQ_GPAIN3		(3)
418c2ecf20Sopenharmony_ci#define IRQ_GPBIN0		(4)
428c2ecf20Sopenharmony_ci#define IRQ_GPBIN1		(5)
438c2ecf20Sopenharmony_ci#define IRQ_GPBIN2		(6)
448c2ecf20Sopenharmony_ci#define IRQ_GPBIN3		(7)
458c2ecf20Sopenharmony_ci#define IRQ_GPBIN4		(8)
468c2ecf20Sopenharmony_ci#define IRQ_GPBIN5		(9)
478c2ecf20Sopenharmony_ci#define IRQ_GPCIN0		(10)
488c2ecf20Sopenharmony_ci#define IRQ_GPCIN1		(11)
498c2ecf20Sopenharmony_ci#define IRQ_GPCIN2		(12)
508c2ecf20Sopenharmony_ci#define IRQ_GPCIN3		(13)
518c2ecf20Sopenharmony_ci#define IRQ_GPCIN4		(14)
528c2ecf20Sopenharmony_ci#define IRQ_GPCIN5		(15)
538c2ecf20Sopenharmony_ci#define IRQ_GPCIN6		(16)
548c2ecf20Sopenharmony_ci#define IRQ_GPCIN7		(17)
558c2ecf20Sopenharmony_ci#define IRQ_MSTXINT		(18)
568c2ecf20Sopenharmony_ci#define IRQ_MSRXINT		(19)
578c2ecf20Sopenharmony_ci#define IRQ_MSSTOPERRINT	(20)
588c2ecf20Sopenharmony_ci#define IRQ_TPTXINT		(21)
598c2ecf20Sopenharmony_ci#define IRQ_TPRXINT		(22)
608c2ecf20Sopenharmony_ci#define IRQ_TPSTOPERRINT	(23)
618c2ecf20Sopenharmony_ci#define SSPXMTINT		(24)
628c2ecf20Sopenharmony_ci#define SSPRCVINT		(25)
638c2ecf20Sopenharmony_ci#define SSPROR			(26)
648c2ecf20Sopenharmony_ci#define AUDXMTDMADONEA		(32)
658c2ecf20Sopenharmony_ci#define AUDRCVDMADONEA		(33)
668c2ecf20Sopenharmony_ci#define AUDXMTDMADONEB		(34)
678c2ecf20Sopenharmony_ci#define AUDRCVDMADONEB		(35)
688c2ecf20Sopenharmony_ci#define AUDTFSR			(36)
698c2ecf20Sopenharmony_ci#define AUDRFSR			(37)
708c2ecf20Sopenharmony_ci#define AUDTUR			(38)
718c2ecf20Sopenharmony_ci#define AUDROR			(39)
728c2ecf20Sopenharmony_ci#define AUDDTS			(40)
738c2ecf20Sopenharmony_ci#define AUDRDD			(41)
748c2ecf20Sopenharmony_ci#define AUDSTO			(42)
758c2ecf20Sopenharmony_ci#define IRQ_USBPWR		(43)
768c2ecf20Sopenharmony_ci#define IRQ_HCIM		(44)
778c2ecf20Sopenharmony_ci#define IRQ_HCIBUFFACC		(45)
788c2ecf20Sopenharmony_ci#define IRQ_HCIRMTWKP		(46)
798c2ecf20Sopenharmony_ci#define IRQ_NHCIMFCIR		(47)
808c2ecf20Sopenharmony_ci#define IRQ_USB_PORT_RESUME	(48)
818c2ecf20Sopenharmony_ci#define IRQ_S0_READY_NINT	(49)
828c2ecf20Sopenharmony_ci#define IRQ_S1_READY_NINT	(50)
838c2ecf20Sopenharmony_ci#define IRQ_S0_CD_VALID		(51)
848c2ecf20Sopenharmony_ci#define IRQ_S1_CD_VALID		(52)
858c2ecf20Sopenharmony_ci#define IRQ_S0_BVD1_STSCHG	(53)
868c2ecf20Sopenharmony_ci#define IRQ_S1_BVD1_STSCHG	(54)
878c2ecf20Sopenharmony_ci#define SA1111_IRQ_NR		(55)
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciextern void sa1110_mb_enable(void);
908c2ecf20Sopenharmony_ciextern void sa1110_mb_disable(void);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/*
938c2ecf20Sopenharmony_ci * We keep the following data for the overall SA1111.  Note that the
948c2ecf20Sopenharmony_ci * struct device and struct resource are "fake"; they should be supplied
958c2ecf20Sopenharmony_ci * by the bus above us.  However, in the interests of getting all SA1111
968c2ecf20Sopenharmony_ci * drivers converted over to the device model, we provide this as an
978c2ecf20Sopenharmony_ci * anchor point for all the other drivers.
988c2ecf20Sopenharmony_ci */
998c2ecf20Sopenharmony_cistruct sa1111 {
1008c2ecf20Sopenharmony_ci	struct device	*dev;
1018c2ecf20Sopenharmony_ci	struct clk	*clk;
1028c2ecf20Sopenharmony_ci	unsigned long	phys;
1038c2ecf20Sopenharmony_ci	int		irq;
1048c2ecf20Sopenharmony_ci	int		irq_base;	/* base for cascaded on-chip IRQs */
1058c2ecf20Sopenharmony_ci	spinlock_t	lock;
1068c2ecf20Sopenharmony_ci	void __iomem	*base;
1078c2ecf20Sopenharmony_ci	struct sa1111_platform_data *pdata;
1088c2ecf20Sopenharmony_ci	struct irq_domain *irqdomain;
1098c2ecf20Sopenharmony_ci	struct gpio_chip gc;
1108c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1118c2ecf20Sopenharmony_ci	void		*saved_state;
1128c2ecf20Sopenharmony_ci#endif
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * We _really_ need to eliminate this.  Its only users
1178c2ecf20Sopenharmony_ci * are the PWM and DMA checking code.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistatic struct sa1111 *g_sa1111;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistruct sa1111_dev_info {
1228c2ecf20Sopenharmony_ci	unsigned long	offset;
1238c2ecf20Sopenharmony_ci	unsigned long	skpcr_mask;
1248c2ecf20Sopenharmony_ci	bool		dma;
1258c2ecf20Sopenharmony_ci	unsigned int	devid;
1268c2ecf20Sopenharmony_ci	unsigned int	hwirq[6];
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic struct sa1111_dev_info sa1111_devices[] = {
1308c2ecf20Sopenharmony_ci	{
1318c2ecf20Sopenharmony_ci		.offset		= SA1111_USB,
1328c2ecf20Sopenharmony_ci		.skpcr_mask	= SKPCR_UCLKEN,
1338c2ecf20Sopenharmony_ci		.dma		= true,
1348c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_USB,
1358c2ecf20Sopenharmony_ci		.hwirq = {
1368c2ecf20Sopenharmony_ci			IRQ_USBPWR,
1378c2ecf20Sopenharmony_ci			IRQ_HCIM,
1388c2ecf20Sopenharmony_ci			IRQ_HCIBUFFACC,
1398c2ecf20Sopenharmony_ci			IRQ_HCIRMTWKP,
1408c2ecf20Sopenharmony_ci			IRQ_NHCIMFCIR,
1418c2ecf20Sopenharmony_ci			IRQ_USB_PORT_RESUME
1428c2ecf20Sopenharmony_ci		},
1438c2ecf20Sopenharmony_ci	},
1448c2ecf20Sopenharmony_ci	{
1458c2ecf20Sopenharmony_ci		.offset		= 0x0600,
1468c2ecf20Sopenharmony_ci		.skpcr_mask	= SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
1478c2ecf20Sopenharmony_ci		.dma		= true,
1488c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_SAC,
1498c2ecf20Sopenharmony_ci		.hwirq = {
1508c2ecf20Sopenharmony_ci			AUDXMTDMADONEA,
1518c2ecf20Sopenharmony_ci			AUDXMTDMADONEB,
1528c2ecf20Sopenharmony_ci			AUDRCVDMADONEA,
1538c2ecf20Sopenharmony_ci			AUDRCVDMADONEB
1548c2ecf20Sopenharmony_ci		},
1558c2ecf20Sopenharmony_ci	},
1568c2ecf20Sopenharmony_ci	{
1578c2ecf20Sopenharmony_ci		.offset		= 0x0800,
1588c2ecf20Sopenharmony_ci		.skpcr_mask	= SKPCR_SCLKEN,
1598c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_SSP,
1608c2ecf20Sopenharmony_ci	},
1618c2ecf20Sopenharmony_ci	{
1628c2ecf20Sopenharmony_ci		.offset		= SA1111_KBD,
1638c2ecf20Sopenharmony_ci		.skpcr_mask	= SKPCR_PTCLKEN,
1648c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_PS2_KBD,
1658c2ecf20Sopenharmony_ci		.hwirq = {
1668c2ecf20Sopenharmony_ci			IRQ_TPRXINT,
1678c2ecf20Sopenharmony_ci			IRQ_TPTXINT
1688c2ecf20Sopenharmony_ci		},
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	{
1718c2ecf20Sopenharmony_ci		.offset		= SA1111_MSE,
1728c2ecf20Sopenharmony_ci		.skpcr_mask	= SKPCR_PMCLKEN,
1738c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_PS2_MSE,
1748c2ecf20Sopenharmony_ci		.hwirq = {
1758c2ecf20Sopenharmony_ci			IRQ_MSRXINT,
1768c2ecf20Sopenharmony_ci			IRQ_MSTXINT
1778c2ecf20Sopenharmony_ci		},
1788c2ecf20Sopenharmony_ci	},
1798c2ecf20Sopenharmony_ci	{
1808c2ecf20Sopenharmony_ci		.offset		= 0x1800,
1818c2ecf20Sopenharmony_ci		.skpcr_mask	= 0,
1828c2ecf20Sopenharmony_ci		.devid		= SA1111_DEVID_PCMCIA,
1838c2ecf20Sopenharmony_ci		.hwirq = {
1848c2ecf20Sopenharmony_ci			IRQ_S0_READY_NINT,
1858c2ecf20Sopenharmony_ci			IRQ_S0_CD_VALID,
1868c2ecf20Sopenharmony_ci			IRQ_S0_BVD1_STSCHG,
1878c2ecf20Sopenharmony_ci			IRQ_S1_READY_NINT,
1888c2ecf20Sopenharmony_ci			IRQ_S1_CD_VALID,
1898c2ecf20Sopenharmony_ci			IRQ_S1_BVD1_STSCHG,
1908c2ecf20Sopenharmony_ci		},
1918c2ecf20Sopenharmony_ci	},
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int sa1111_map_irq(struct sa1111 *sachip, irq_hw_number_t hwirq)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	return irq_create_mapping(sachip->irqdomain, hwirq);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void sa1111_handle_irqdomain(struct irq_domain *irqdomain, int irq)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct irq_desc *d = irq_to_desc(irq_linear_revmap(irqdomain, irq));
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (d)
2048c2ecf20Sopenharmony_ci		generic_handle_irq_desc(d);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/*
2088c2ecf20Sopenharmony_ci * SA1111 interrupt support.  Since clearing an IRQ while there are
2098c2ecf20Sopenharmony_ci * active IRQs causes the interrupt output to pulse, the upper levels
2108c2ecf20Sopenharmony_ci * will call us again if there are more interrupts to process.
2118c2ecf20Sopenharmony_ci */
2128c2ecf20Sopenharmony_cistatic void sa1111_irq_handler(struct irq_desc *desc)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	unsigned int stat0, stat1, i;
2158c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_desc_get_handler_data(desc);
2168c2ecf20Sopenharmony_ci	struct irq_domain *irqdomain;
2178c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	stat0 = readl_relaxed(mapbase + SA1111_INTSTATCLR0);
2208c2ecf20Sopenharmony_ci	stat1 = readl_relaxed(mapbase + SA1111_INTSTATCLR1);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	writel_relaxed(stat0, mapbase + SA1111_INTSTATCLR0);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	desc->irq_data.chip->irq_ack(&desc->irq_data);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	writel_relaxed(stat1, mapbase + SA1111_INTSTATCLR1);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (stat0 == 0 && stat1 == 0) {
2298c2ecf20Sopenharmony_ci		do_bad_IRQ(desc);
2308c2ecf20Sopenharmony_ci		return;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	irqdomain = sachip->irqdomain;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	for (i = 0; stat0; i++, stat0 >>= 1)
2368c2ecf20Sopenharmony_ci		if (stat0 & 1)
2378c2ecf20Sopenharmony_ci			sa1111_handle_irqdomain(irqdomain, i);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	for (i = 32; stat1; i++, stat1 >>= 1)
2408c2ecf20Sopenharmony_ci		if (stat1 & 1)
2418c2ecf20Sopenharmony_ci			sa1111_handle_irqdomain(irqdomain, i);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* For level-based interrupts */
2448c2ecf20Sopenharmony_ci	desc->irq_data.chip->irq_unmask(&desc->irq_data);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic u32 sa1111_irqmask(struct irq_data *d)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	return BIT(irqd_to_hwirq(d) & 31);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic int sa1111_irqbank(struct irq_data *d)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	return (irqd_to_hwirq(d) / 32) * 4;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void sa1111_ack_irq(struct irq_data *d)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void sa1111_mask_irq(struct irq_data *d)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
2648c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
2658c2ecf20Sopenharmony_ci	u32 ie;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	ie = readl_relaxed(mapbase + SA1111_INTEN0);
2688c2ecf20Sopenharmony_ci	ie &= ~sa1111_irqmask(d);
2698c2ecf20Sopenharmony_ci	writel(ie, mapbase + SA1111_INTEN0);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void sa1111_unmask_irq(struct irq_data *d)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
2758c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
2768c2ecf20Sopenharmony_ci	u32 ie;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	ie = readl_relaxed(mapbase + SA1111_INTEN0);
2798c2ecf20Sopenharmony_ci	ie |= sa1111_irqmask(d);
2808c2ecf20Sopenharmony_ci	writel_relaxed(ie, mapbase + SA1111_INTEN0);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/*
2848c2ecf20Sopenharmony_ci * Attempt to re-trigger the interrupt.  The SA1111 contains a register
2858c2ecf20Sopenharmony_ci * (INTSET) which claims to do this.  However, in practice no amount of
2868c2ecf20Sopenharmony_ci * manipulation of INTEN and INTSET guarantees that the interrupt will
2878c2ecf20Sopenharmony_ci * be triggered.  In fact, its very difficult, if not impossible to get
2888c2ecf20Sopenharmony_ci * INTSET to re-trigger the interrupt.
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_cistatic int sa1111_retrigger_irq(struct irq_data *d)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
2938c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
2948c2ecf20Sopenharmony_ci	u32 ip, mask = sa1111_irqmask(d);
2958c2ecf20Sopenharmony_ci	int i;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	ip = readl_relaxed(mapbase + SA1111_INTPOL0);
2988c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
2998c2ecf20Sopenharmony_ci		writel_relaxed(ip ^ mask, mapbase + SA1111_INTPOL0);
3008c2ecf20Sopenharmony_ci		writel_relaxed(ip, mapbase + SA1111_INTPOL0);
3018c2ecf20Sopenharmony_ci		if (readl_relaxed(mapbase + SA1111_INTSTATCLR0) & mask)
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (i == 8) {
3068c2ecf20Sopenharmony_ci		pr_err("Danger Will Robinson: failed to re-trigger IRQ%d\n",
3078c2ecf20Sopenharmony_ci		       d->irq);
3088c2ecf20Sopenharmony_ci		return 0;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return 1;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int sa1111_type_irq(struct irq_data *d, unsigned int flags)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
3178c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
3188c2ecf20Sopenharmony_ci	u32 ip, mask = sa1111_irqmask(d);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (flags == IRQ_TYPE_PROBE)
3218c2ecf20Sopenharmony_ci		return 0;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if ((!(flags & IRQ_TYPE_EDGE_RISING) ^ !(flags & IRQ_TYPE_EDGE_FALLING)) == 0)
3248c2ecf20Sopenharmony_ci		return -EINVAL;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	ip = readl_relaxed(mapbase + SA1111_INTPOL0);
3278c2ecf20Sopenharmony_ci	if (flags & IRQ_TYPE_EDGE_RISING)
3288c2ecf20Sopenharmony_ci		ip &= ~mask;
3298c2ecf20Sopenharmony_ci	else
3308c2ecf20Sopenharmony_ci		ip |= mask;
3318c2ecf20Sopenharmony_ci	writel_relaxed(ip, mapbase + SA1111_INTPOL0);
3328c2ecf20Sopenharmony_ci	writel_relaxed(ip, mapbase + SA1111_WAKEPOL0);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int sa1111_wake_irq(struct irq_data *d, unsigned int on)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
3408c2ecf20Sopenharmony_ci	void __iomem *mapbase = sachip->base + SA1111_INTC + sa1111_irqbank(d);
3418c2ecf20Sopenharmony_ci	u32 we, mask = sa1111_irqmask(d);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	we = readl_relaxed(mapbase + SA1111_WAKEEN0);
3448c2ecf20Sopenharmony_ci	if (on)
3458c2ecf20Sopenharmony_ci		we |= mask;
3468c2ecf20Sopenharmony_ci	else
3478c2ecf20Sopenharmony_ci		we &= ~mask;
3488c2ecf20Sopenharmony_ci	writel_relaxed(we, mapbase + SA1111_WAKEEN0);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic struct irq_chip sa1111_irq_chip = {
3548c2ecf20Sopenharmony_ci	.name		= "SA1111",
3558c2ecf20Sopenharmony_ci	.irq_ack	= sa1111_ack_irq,
3568c2ecf20Sopenharmony_ci	.irq_mask	= sa1111_mask_irq,
3578c2ecf20Sopenharmony_ci	.irq_unmask	= sa1111_unmask_irq,
3588c2ecf20Sopenharmony_ci	.irq_retrigger	= sa1111_retrigger_irq,
3598c2ecf20Sopenharmony_ci	.irq_set_type	= sa1111_type_irq,
3608c2ecf20Sopenharmony_ci	.irq_set_wake	= sa1111_wake_irq,
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic int sa1111_irqdomain_map(struct irq_domain *d, unsigned int irq,
3648c2ecf20Sopenharmony_ci	irq_hw_number_t hwirq)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct sa1111 *sachip = d->host_data;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* Disallow unavailable interrupts */
3698c2ecf20Sopenharmony_ci	if (hwirq > SSPROR && hwirq < AUDXMTDMADONEA)
3708c2ecf20Sopenharmony_ci		return -EINVAL;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	irq_set_chip_data(irq, sachip);
3738c2ecf20Sopenharmony_ci	irq_set_chip_and_handler(irq, &sa1111_irq_chip, handle_edge_irq);
3748c2ecf20Sopenharmony_ci	irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	return 0;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic const struct irq_domain_ops sa1111_irqdomain_ops = {
3808c2ecf20Sopenharmony_ci	.map = sa1111_irqdomain_map,
3818c2ecf20Sopenharmony_ci	.xlate = irq_domain_xlate_twocell,
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	void __iomem *irqbase = sachip->base + SA1111_INTC;
3878c2ecf20Sopenharmony_ci	int ret;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/*
3908c2ecf20Sopenharmony_ci	 * We're guaranteed that this region hasn't been taken.
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	request_mem_region(sachip->phys + SA1111_INTC, 512, "irq");
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	ret = irq_alloc_descs(-1, irq_base, SA1111_IRQ_NR, -1);
3958c2ecf20Sopenharmony_ci	if (ret <= 0) {
3968c2ecf20Sopenharmony_ci		dev_err(sachip->dev, "unable to allocate %u irqs: %d\n",
3978c2ecf20Sopenharmony_ci			SA1111_IRQ_NR, ret);
3988c2ecf20Sopenharmony_ci		if (ret == 0)
3998c2ecf20Sopenharmony_ci			ret = -EINVAL;
4008c2ecf20Sopenharmony_ci		return ret;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	sachip->irq_base = ret;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* disable all IRQs */
4068c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_INTEN0);
4078c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_INTEN1);
4088c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_WAKEEN0);
4098c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_WAKEEN1);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/*
4128c2ecf20Sopenharmony_ci	 * detect on rising edge.  Note: Feb 2001 Errata for SA1111
4138c2ecf20Sopenharmony_ci	 * specifies that S0ReadyInt and S1ReadyInt should be '1'.
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_INTPOL0);
4168c2ecf20Sopenharmony_ci	writel_relaxed(BIT(IRQ_S0_READY_NINT & 31) |
4178c2ecf20Sopenharmony_ci		       BIT(IRQ_S1_READY_NINT & 31),
4188c2ecf20Sopenharmony_ci		       irqbase + SA1111_INTPOL1);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* clear all IRQs */
4218c2ecf20Sopenharmony_ci	writel_relaxed(~0, irqbase + SA1111_INTSTATCLR0);
4228c2ecf20Sopenharmony_ci	writel_relaxed(~0, irqbase + SA1111_INTSTATCLR1);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	sachip->irqdomain = irq_domain_add_linear(NULL, SA1111_IRQ_NR,
4258c2ecf20Sopenharmony_ci						  &sa1111_irqdomain_ops,
4268c2ecf20Sopenharmony_ci						  sachip);
4278c2ecf20Sopenharmony_ci	if (!sachip->irqdomain) {
4288c2ecf20Sopenharmony_ci		irq_free_descs(sachip->irq_base, SA1111_IRQ_NR);
4298c2ecf20Sopenharmony_ci		return -ENOMEM;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	irq_domain_associate_many(sachip->irqdomain,
4338c2ecf20Sopenharmony_ci				  sachip->irq_base + IRQ_GPAIN0,
4348c2ecf20Sopenharmony_ci				  IRQ_GPAIN0, SSPROR + 1 - IRQ_GPAIN0);
4358c2ecf20Sopenharmony_ci	irq_domain_associate_many(sachip->irqdomain,
4368c2ecf20Sopenharmony_ci				  sachip->irq_base + AUDXMTDMADONEA,
4378c2ecf20Sopenharmony_ci				  AUDXMTDMADONEA,
4388c2ecf20Sopenharmony_ci				  IRQ_S1_BVD1_STSCHG + 1 - AUDXMTDMADONEA);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * Register SA1111 interrupt
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING);
4448c2ecf20Sopenharmony_ci	irq_set_chained_handler_and_data(sachip->irq, sa1111_irq_handler,
4458c2ecf20Sopenharmony_ci					 sachip);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	dev_info(sachip->dev, "Providing IRQ%u-%u\n",
4488c2ecf20Sopenharmony_ci		sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void sa1111_remove_irq(struct sa1111 *sachip)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct irq_domain *domain = sachip->irqdomain;
4568c2ecf20Sopenharmony_ci	void __iomem *irqbase = sachip->base + SA1111_INTC;
4578c2ecf20Sopenharmony_ci	int i;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* disable all IRQs */
4608c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_INTEN0);
4618c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_INTEN1);
4628c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_WAKEEN0);
4638c2ecf20Sopenharmony_ci	writel_relaxed(0, irqbase + SA1111_WAKEEN1);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	irq_set_chained_handler_and_data(sachip->irq, NULL, NULL);
4668c2ecf20Sopenharmony_ci	for (i = 0; i < SA1111_IRQ_NR; i++)
4678c2ecf20Sopenharmony_ci		irq_dispose_mapping(irq_find_mapping(domain, i));
4688c2ecf20Sopenharmony_ci	irq_domain_remove(domain);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	release_mem_region(sachip->phys + SA1111_INTC, 512);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cienum {
4748c2ecf20Sopenharmony_ci	SA1111_GPIO_PXDDR = (SA1111_GPIO_PADDR - SA1111_GPIO_PADDR),
4758c2ecf20Sopenharmony_ci	SA1111_GPIO_PXDRR = (SA1111_GPIO_PADRR - SA1111_GPIO_PADDR),
4768c2ecf20Sopenharmony_ci	SA1111_GPIO_PXDWR = (SA1111_GPIO_PADWR - SA1111_GPIO_PADDR),
4778c2ecf20Sopenharmony_ci	SA1111_GPIO_PXSDR = (SA1111_GPIO_PASDR - SA1111_GPIO_PADDR),
4788c2ecf20Sopenharmony_ci	SA1111_GPIO_PXSSR = (SA1111_GPIO_PASSR - SA1111_GPIO_PADDR),
4798c2ecf20Sopenharmony_ci};
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic struct sa1111 *gc_to_sa1111(struct gpio_chip *gc)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	return container_of(gc, struct sa1111, gc);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic void __iomem *sa1111_gpio_map_reg(struct sa1111 *sachip, unsigned offset)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	void __iomem *reg = sachip->base + SA1111_GPIO;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (offset < 4)
4918c2ecf20Sopenharmony_ci		return reg + SA1111_GPIO_PADDR;
4928c2ecf20Sopenharmony_ci	if (offset < 10)
4938c2ecf20Sopenharmony_ci		return reg + SA1111_GPIO_PBDDR;
4948c2ecf20Sopenharmony_ci	if (offset < 18)
4958c2ecf20Sopenharmony_ci		return reg + SA1111_GPIO_PCDDR;
4968c2ecf20Sopenharmony_ci	return NULL;
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic u32 sa1111_gpio_map_bit(unsigned offset)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	if (offset < 4)
5028c2ecf20Sopenharmony_ci		return BIT(offset);
5038c2ecf20Sopenharmony_ci	if (offset < 10)
5048c2ecf20Sopenharmony_ci		return BIT(offset - 4);
5058c2ecf20Sopenharmony_ci	if (offset < 18)
5068c2ecf20Sopenharmony_ci		return BIT(offset - 10);
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic void sa1111_gpio_modify(void __iomem *reg, u32 mask, u32 set)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	u32 val;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	val = readl_relaxed(reg);
5158c2ecf20Sopenharmony_ci	val &= ~mask;
5168c2ecf20Sopenharmony_ci	val |= mask & set;
5178c2ecf20Sopenharmony_ci	writel_relaxed(val, reg);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int sa1111_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5238c2ecf20Sopenharmony_ci	void __iomem *reg = sa1111_gpio_map_reg(sachip, offset);
5248c2ecf20Sopenharmony_ci	u32 mask = sa1111_gpio_map_bit(offset);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return !!(readl_relaxed(reg + SA1111_GPIO_PXDDR) & mask);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int sa1111_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5328c2ecf20Sopenharmony_ci	unsigned long flags;
5338c2ecf20Sopenharmony_ci	void __iomem *reg = sa1111_gpio_map_reg(sachip, offset);
5348c2ecf20Sopenharmony_ci	u32 mask = sa1111_gpio_map_bit(offset);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
5378c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXDDR, mask, mask);
5388c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXSDR, mask, mask);
5398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return 0;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int sa1111_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
5458c2ecf20Sopenharmony_ci	int value)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5488c2ecf20Sopenharmony_ci	unsigned long flags;
5498c2ecf20Sopenharmony_ci	void __iomem *reg = sa1111_gpio_map_reg(sachip, offset);
5508c2ecf20Sopenharmony_ci	u32 mask = sa1111_gpio_map_bit(offset);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
5538c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXDWR, mask, value ? mask : 0);
5548c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXSSR, mask, value ? mask : 0);
5558c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXDDR, mask, 0);
5568c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXSDR, mask, 0);
5578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	return 0;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic int sa1111_gpio_get(struct gpio_chip *gc, unsigned offset)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5658c2ecf20Sopenharmony_ci	void __iomem *reg = sa1111_gpio_map_reg(sachip, offset);
5668c2ecf20Sopenharmony_ci	u32 mask = sa1111_gpio_map_bit(offset);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	return !!(readl_relaxed(reg + SA1111_GPIO_PXDRR) & mask);
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic void sa1111_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5748c2ecf20Sopenharmony_ci	unsigned long flags;
5758c2ecf20Sopenharmony_ci	void __iomem *reg = sa1111_gpio_map_reg(sachip, offset);
5768c2ecf20Sopenharmony_ci	u32 mask = sa1111_gpio_map_bit(offset);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
5798c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXDWR, mask, value ? mask : 0);
5808c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PXSSR, mask, value ? mask : 0);
5818c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic void sa1111_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
5858c2ecf20Sopenharmony_ci	unsigned long *bits)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
5888c2ecf20Sopenharmony_ci	unsigned long flags;
5898c2ecf20Sopenharmony_ci	void __iomem *reg = sachip->base + SA1111_GPIO;
5908c2ecf20Sopenharmony_ci	u32 msk, val;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	msk = *mask;
5938c2ecf20Sopenharmony_ci	val = *bits;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
5968c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PADWR, msk & 15, val);
5978c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PASSR, msk & 15, val);
5988c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PBDWR, (msk >> 4) & 255, val >> 4);
5998c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PBSSR, (msk >> 4) & 255, val >> 4);
6008c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PCDWR, (msk >> 12) & 255, val >> 12);
6018c2ecf20Sopenharmony_ci	sa1111_gpio_modify(reg + SA1111_GPIO_PCSSR, (msk >> 12) & 255, val >> 12);
6028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int sa1111_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct sa1111 *sachip = gc_to_sa1111(gc);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	return sa1111_map_irq(sachip, offset);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int sa1111_setup_gpios(struct sa1111 *sachip)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	sachip->gc.label = "sa1111";
6158c2ecf20Sopenharmony_ci	sachip->gc.parent = sachip->dev;
6168c2ecf20Sopenharmony_ci	sachip->gc.owner = THIS_MODULE;
6178c2ecf20Sopenharmony_ci	sachip->gc.get_direction = sa1111_gpio_get_direction;
6188c2ecf20Sopenharmony_ci	sachip->gc.direction_input = sa1111_gpio_direction_input;
6198c2ecf20Sopenharmony_ci	sachip->gc.direction_output = sa1111_gpio_direction_output;
6208c2ecf20Sopenharmony_ci	sachip->gc.get = sa1111_gpio_get;
6218c2ecf20Sopenharmony_ci	sachip->gc.set = sa1111_gpio_set;
6228c2ecf20Sopenharmony_ci	sachip->gc.set_multiple = sa1111_gpio_set_multiple;
6238c2ecf20Sopenharmony_ci	sachip->gc.to_irq = sa1111_gpio_to_irq;
6248c2ecf20Sopenharmony_ci	sachip->gc.base = -1;
6258c2ecf20Sopenharmony_ci	sachip->gc.ngpio = 18;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	return devm_gpiochip_add_data(sachip->dev, &sachip->gc, sachip);
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci/*
6318c2ecf20Sopenharmony_ci * Bring the SA1111 out of reset.  This requires a set procedure:
6328c2ecf20Sopenharmony_ci *  1. nRESET asserted (by hardware)
6338c2ecf20Sopenharmony_ci *  2. CLK turned on from SA1110
6348c2ecf20Sopenharmony_ci *  3. nRESET deasserted
6358c2ecf20Sopenharmony_ci *  4. VCO turned on, PLL_BYPASS turned off
6368c2ecf20Sopenharmony_ci *  5. Wait lock time, then assert RCLKEn
6378c2ecf20Sopenharmony_ci *  7. PCR set to allow clocking of individual functions
6388c2ecf20Sopenharmony_ci *
6398c2ecf20Sopenharmony_ci * Until we've done this, the only registers we can access are:
6408c2ecf20Sopenharmony_ci *   SBI_SKCR
6418c2ecf20Sopenharmony_ci *   SBI_SMCR
6428c2ecf20Sopenharmony_ci *   SBI_SKID
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_cistatic void sa1111_wake(struct sa1111 *sachip)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	unsigned long flags, r;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	clk_enable(sachip->clk);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/*
6538c2ecf20Sopenharmony_ci	 * Turn VCO on, and disable PLL Bypass.
6548c2ecf20Sopenharmony_ci	 */
6558c2ecf20Sopenharmony_ci	r = readl_relaxed(sachip->base + SA1111_SKCR);
6568c2ecf20Sopenharmony_ci	r &= ~SKCR_VCO_OFF;
6578c2ecf20Sopenharmony_ci	writel_relaxed(r, sachip->base + SA1111_SKCR);
6588c2ecf20Sopenharmony_ci	r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
6598c2ecf20Sopenharmony_ci	writel_relaxed(r, sachip->base + SA1111_SKCR);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	/*
6628c2ecf20Sopenharmony_ci	 * Wait lock time.  SA1111 manual _doesn't_
6638c2ecf20Sopenharmony_ci	 * specify a figure for this!  We choose 100us.
6648c2ecf20Sopenharmony_ci	 */
6658c2ecf20Sopenharmony_ci	udelay(100);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	/*
6688c2ecf20Sopenharmony_ci	 * Enable RCLK.  We also ensure that RDYEN is set.
6698c2ecf20Sopenharmony_ci	 */
6708c2ecf20Sopenharmony_ci	r |= SKCR_RCLKEN | SKCR_RDYEN;
6718c2ecf20Sopenharmony_ci	writel_relaxed(r, sachip->base + SA1111_SKCR);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	/*
6748c2ecf20Sopenharmony_ci	 * Wait 14 RCLK cycles for the chip to finish coming out
6758c2ecf20Sopenharmony_ci	 * of reset. (RCLK=24MHz).  This is 590ns.
6768c2ecf20Sopenharmony_ci	 */
6778c2ecf20Sopenharmony_ci	udelay(1);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	/*
6808c2ecf20Sopenharmony_ci	 * Ensure all clocks are initially off.
6818c2ecf20Sopenharmony_ci	 */
6828c2ecf20Sopenharmony_ci	writel_relaxed(0, sachip->base + SA1111_SKPCR);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_SA1100
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_cistatic u32 sa1111_dma_mask[] = {
6908c2ecf20Sopenharmony_ci	~0,
6918c2ecf20Sopenharmony_ci	~(1 << 20),
6928c2ecf20Sopenharmony_ci	~(1 << 23),
6938c2ecf20Sopenharmony_ci	~(1 << 24),
6948c2ecf20Sopenharmony_ci	~(1 << 25),
6958c2ecf20Sopenharmony_ci	~(1 << 20),
6968c2ecf20Sopenharmony_ci	~(1 << 20),
6978c2ecf20Sopenharmony_ci	0,
6988c2ecf20Sopenharmony_ci};
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/*
7018c2ecf20Sopenharmony_ci * Configure the SA1111 shared memory controller.
7028c2ecf20Sopenharmony_ci */
7038c2ecf20Sopenharmony_civoid
7048c2ecf20Sopenharmony_cisa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
7058c2ecf20Sopenharmony_ci		     unsigned int cas_latency)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (cas_latency == 3)
7108c2ecf20Sopenharmony_ci		smcr |= SMCR_CLAT;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	writel_relaxed(smcr, sachip->base + SA1111_SMCR);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 * Now clear the bits in the DMA mask to work around the SA1111
7168c2ecf20Sopenharmony_ci	 * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion
7178c2ecf20Sopenharmony_ci	 * Chip Specification Update, June 2000, Erratum #7).
7188c2ecf20Sopenharmony_ci	 */
7198c2ecf20Sopenharmony_ci	if (sachip->dev->dma_mask)
7208c2ecf20Sopenharmony_ci		*sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2];
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2];
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci#endif
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic void sa1111_dev_release(struct device *_dev)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct sa1111_dev *dev = to_sa1111_device(_dev);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	kfree(dev);
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic int
7348c2ecf20Sopenharmony_cisa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
7358c2ecf20Sopenharmony_ci		      struct sa1111_dev_info *info)
7368c2ecf20Sopenharmony_ci{
7378c2ecf20Sopenharmony_ci	struct sa1111_dev *dev;
7388c2ecf20Sopenharmony_ci	unsigned i;
7398c2ecf20Sopenharmony_ci	int ret;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(struct sa1111_dev), GFP_KERNEL);
7428c2ecf20Sopenharmony_ci	if (!dev) {
7438c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7448c2ecf20Sopenharmony_ci		goto err_alloc;
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	device_initialize(&dev->dev);
7488c2ecf20Sopenharmony_ci	dev_set_name(&dev->dev, "%4.4lx", info->offset);
7498c2ecf20Sopenharmony_ci	dev->devid	 = info->devid;
7508c2ecf20Sopenharmony_ci	dev->dev.parent  = sachip->dev;
7518c2ecf20Sopenharmony_ci	dev->dev.bus     = &sa1111_bus_type;
7528c2ecf20Sopenharmony_ci	dev->dev.release = sa1111_dev_release;
7538c2ecf20Sopenharmony_ci	dev->res.start   = sachip->phys + info->offset;
7548c2ecf20Sopenharmony_ci	dev->res.end     = dev->res.start + 511;
7558c2ecf20Sopenharmony_ci	dev->res.name    = dev_name(&dev->dev);
7568c2ecf20Sopenharmony_ci	dev->res.flags   = IORESOURCE_MEM;
7578c2ecf20Sopenharmony_ci	dev->mapbase     = sachip->base + info->offset;
7588c2ecf20Sopenharmony_ci	dev->skpcr_mask  = info->skpcr_mask;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(info->hwirq); i++)
7618c2ecf20Sopenharmony_ci		dev->hwirq[i] = info->hwirq[i];
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/*
7648c2ecf20Sopenharmony_ci	 * If the parent device has a DMA mask associated with it, and
7658c2ecf20Sopenharmony_ci	 * this child supports DMA, propagate it down to the children.
7668c2ecf20Sopenharmony_ci	 */
7678c2ecf20Sopenharmony_ci	if (info->dma && sachip->dev->dma_mask) {
7688c2ecf20Sopenharmony_ci		dev->dma_mask = *sachip->dev->dma_mask;
7698c2ecf20Sopenharmony_ci		dev->dev.dma_mask = &dev->dma_mask;
7708c2ecf20Sopenharmony_ci		dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	ret = request_resource(parent, &dev->res);
7748c2ecf20Sopenharmony_ci	if (ret) {
7758c2ecf20Sopenharmony_ci		dev_err(sachip->dev, "failed to allocate resource for %s\n",
7768c2ecf20Sopenharmony_ci			dev->res.name);
7778c2ecf20Sopenharmony_ci		goto err_resource;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	ret = device_add(&dev->dev);
7818c2ecf20Sopenharmony_ci	if (ret)
7828c2ecf20Sopenharmony_ci		goto err_add;
7838c2ecf20Sopenharmony_ci	return 0;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci err_add:
7868c2ecf20Sopenharmony_ci	release_resource(&dev->res);
7878c2ecf20Sopenharmony_ci err_resource:
7888c2ecf20Sopenharmony_ci	put_device(&dev->dev);
7898c2ecf20Sopenharmony_ci err_alloc:
7908c2ecf20Sopenharmony_ci	return ret;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/**
7948c2ecf20Sopenharmony_ci *	sa1111_probe - probe for a single SA1111 chip.
7958c2ecf20Sopenharmony_ci *	@phys_addr: physical address of device.
7968c2ecf20Sopenharmony_ci *
7978c2ecf20Sopenharmony_ci *	Probe for a SA1111 chip.  This must be called
7988c2ecf20Sopenharmony_ci *	before any other SA1111-specific code.
7998c2ecf20Sopenharmony_ci *
8008c2ecf20Sopenharmony_ci *	Returns:
8018c2ecf20Sopenharmony_ci *	%-ENODEV	device not found.
8028c2ecf20Sopenharmony_ci *	%-EBUSY		physical address already marked in-use.
8038c2ecf20Sopenharmony_ci *	%-EINVAL	no platform data passed
8048c2ecf20Sopenharmony_ci *	%0		successful.
8058c2ecf20Sopenharmony_ci */
8068c2ecf20Sopenharmony_cistatic int __sa1111_probe(struct device *me, struct resource *mem, int irq)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	struct sa1111_platform_data *pd = me->platform_data;
8098c2ecf20Sopenharmony_ci	struct sa1111 *sachip;
8108c2ecf20Sopenharmony_ci	unsigned long id;
8118c2ecf20Sopenharmony_ci	unsigned int has_devs;
8128c2ecf20Sopenharmony_ci	int i, ret = -ENODEV;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (!pd)
8158c2ecf20Sopenharmony_ci		return -EINVAL;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	sachip = devm_kzalloc(me, sizeof(struct sa1111), GFP_KERNEL);
8188c2ecf20Sopenharmony_ci	if (!sachip)
8198c2ecf20Sopenharmony_ci		return -ENOMEM;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	sachip->clk = devm_clk_get(me, "SA1111_CLK");
8228c2ecf20Sopenharmony_ci	if (IS_ERR(sachip->clk))
8238c2ecf20Sopenharmony_ci		return PTR_ERR(sachip->clk);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	ret = clk_prepare(sachip->clk);
8268c2ecf20Sopenharmony_ci	if (ret)
8278c2ecf20Sopenharmony_ci		return ret;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	spin_lock_init(&sachip->lock);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	sachip->dev = me;
8328c2ecf20Sopenharmony_ci	dev_set_drvdata(sachip->dev, sachip);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	sachip->pdata = pd;
8358c2ecf20Sopenharmony_ci	sachip->phys = mem->start;
8368c2ecf20Sopenharmony_ci	sachip->irq = irq;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	/*
8398c2ecf20Sopenharmony_ci	 * Map the whole region.  This also maps the
8408c2ecf20Sopenharmony_ci	 * registers for our children.
8418c2ecf20Sopenharmony_ci	 */
8428c2ecf20Sopenharmony_ci	sachip->base = ioremap(mem->start, PAGE_SIZE * 2);
8438c2ecf20Sopenharmony_ci	if (!sachip->base) {
8448c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8458c2ecf20Sopenharmony_ci		goto err_clk_unprep;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/*
8498c2ecf20Sopenharmony_ci	 * Probe for the chip.  Only touch the SBI registers.
8508c2ecf20Sopenharmony_ci	 */
8518c2ecf20Sopenharmony_ci	id = readl_relaxed(sachip->base + SA1111_SKID);
8528c2ecf20Sopenharmony_ci	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
8538c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
8548c2ecf20Sopenharmony_ci		ret = -ENODEV;
8558c2ecf20Sopenharmony_ci		goto err_unmap;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	pr_info("SA1111 Microprocessor Companion Chip: silicon revision %lx, metal revision %lx\n",
8598c2ecf20Sopenharmony_ci		(id & SKID_SIREV_MASK) >> 4, id & SKID_MTREV_MASK);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	/*
8628c2ecf20Sopenharmony_ci	 * We found it.  Wake the chip up, and initialise.
8638c2ecf20Sopenharmony_ci	 */
8648c2ecf20Sopenharmony_ci	sa1111_wake(sachip);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/*
8678c2ecf20Sopenharmony_ci	 * The interrupt controller must be initialised before any
8688c2ecf20Sopenharmony_ci	 * other device to ensure that the interrupts are available.
8698c2ecf20Sopenharmony_ci	 */
8708c2ecf20Sopenharmony_ci	ret = sa1111_setup_irq(sachip, pd->irq_base);
8718c2ecf20Sopenharmony_ci	if (ret)
8728c2ecf20Sopenharmony_ci		goto err_clk;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* Setup the GPIOs - should really be done after the IRQ setup */
8758c2ecf20Sopenharmony_ci	ret = sa1111_setup_gpios(sachip);
8768c2ecf20Sopenharmony_ci	if (ret)
8778c2ecf20Sopenharmony_ci		goto err_irq;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_SA1100
8808c2ecf20Sopenharmony_ci	{
8818c2ecf20Sopenharmony_ci	unsigned int val;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	/*
8848c2ecf20Sopenharmony_ci	 * The SDRAM configuration of the SA1110 and the SA1111 must
8858c2ecf20Sopenharmony_ci	 * match.  This is very important to ensure that SA1111 accesses
8868c2ecf20Sopenharmony_ci	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
8878c2ecf20Sopenharmony_ci	 * MBGNT signal, so we must have called sa1110_mb_disable()
8888c2ecf20Sopenharmony_ci	 * beforehand.
8898c2ecf20Sopenharmony_ci	 */
8908c2ecf20Sopenharmony_ci	sa1111_configure_smc(sachip, 1,
8918c2ecf20Sopenharmony_ci			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
8928c2ecf20Sopenharmony_ci			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/*
8958c2ecf20Sopenharmony_ci	 * We only need to turn on DCLK whenever we want to use the
8968c2ecf20Sopenharmony_ci	 * DMA.  It can otherwise be held firmly in the off position.
8978c2ecf20Sopenharmony_ci	 * (currently, we always enable it.)
8988c2ecf20Sopenharmony_ci	 */
8998c2ecf20Sopenharmony_ci	val = readl_relaxed(sachip->base + SA1111_SKPCR);
9008c2ecf20Sopenharmony_ci	writel_relaxed(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	/*
9038c2ecf20Sopenharmony_ci	 * Enable the SA1110 memory bus request and grant signals.
9048c2ecf20Sopenharmony_ci	 */
9058c2ecf20Sopenharmony_ci	sa1110_mb_enable();
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci#endif
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	g_sa1111 = sachip;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	has_devs = ~0;
9128c2ecf20Sopenharmony_ci	if (pd)
9138c2ecf20Sopenharmony_ci		has_devs &= ~pd->disable_devs;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sa1111_devices); i++)
9168c2ecf20Sopenharmony_ci		if (sa1111_devices[i].devid & has_devs)
9178c2ecf20Sopenharmony_ci			sa1111_init_one_child(sachip, mem, &sa1111_devices[i]);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	return 0;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci err_irq:
9228c2ecf20Sopenharmony_ci	sa1111_remove_irq(sachip);
9238c2ecf20Sopenharmony_ci err_clk:
9248c2ecf20Sopenharmony_ci	clk_disable(sachip->clk);
9258c2ecf20Sopenharmony_ci err_unmap:
9268c2ecf20Sopenharmony_ci	iounmap(sachip->base);
9278c2ecf20Sopenharmony_ci err_clk_unprep:
9288c2ecf20Sopenharmony_ci	clk_unprepare(sachip->clk);
9298c2ecf20Sopenharmony_ci	return ret;
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_cistatic int sa1111_remove_one(struct device *dev, void *data)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct sa1111_dev *sadev = to_sa1111_device(dev);
9358c2ecf20Sopenharmony_ci	if (dev->bus != &sa1111_bus_type)
9368c2ecf20Sopenharmony_ci		return 0;
9378c2ecf20Sopenharmony_ci	device_del(&sadev->dev);
9388c2ecf20Sopenharmony_ci	release_resource(&sadev->res);
9398c2ecf20Sopenharmony_ci	put_device(&sadev->dev);
9408c2ecf20Sopenharmony_ci	return 0;
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic void __sa1111_remove(struct sa1111 *sachip)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	device_for_each_child(sachip->dev, NULL, sa1111_remove_one);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	sa1111_remove_irq(sachip);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	clk_disable(sachip->clk);
9508c2ecf20Sopenharmony_ci	clk_unprepare(sachip->clk);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	iounmap(sachip->base);
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistruct sa1111_save_data {
9568c2ecf20Sopenharmony_ci	unsigned int	skcr;
9578c2ecf20Sopenharmony_ci	unsigned int	skpcr;
9588c2ecf20Sopenharmony_ci	unsigned int	skcdr;
9598c2ecf20Sopenharmony_ci	unsigned char	skaud;
9608c2ecf20Sopenharmony_ci	unsigned char	skpwm0;
9618c2ecf20Sopenharmony_ci	unsigned char	skpwm1;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	/*
9648c2ecf20Sopenharmony_ci	 * Interrupt controller
9658c2ecf20Sopenharmony_ci	 */
9668c2ecf20Sopenharmony_ci	unsigned int	intpol0;
9678c2ecf20Sopenharmony_ci	unsigned int	intpol1;
9688c2ecf20Sopenharmony_ci	unsigned int	inten0;
9698c2ecf20Sopenharmony_ci	unsigned int	inten1;
9708c2ecf20Sopenharmony_ci	unsigned int	wakepol0;
9718c2ecf20Sopenharmony_ci	unsigned int	wakepol1;
9728c2ecf20Sopenharmony_ci	unsigned int	wakeen0;
9738c2ecf20Sopenharmony_ci	unsigned int	wakeen1;
9748c2ecf20Sopenharmony_ci};
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic int sa1111_suspend_noirq(struct device *dev)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct sa1111 *sachip = dev_get_drvdata(dev);
9818c2ecf20Sopenharmony_ci	struct sa1111_save_data *save;
9828c2ecf20Sopenharmony_ci	unsigned long flags;
9838c2ecf20Sopenharmony_ci	unsigned int val;
9848c2ecf20Sopenharmony_ci	void __iomem *base;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
9878c2ecf20Sopenharmony_ci	if (!save)
9888c2ecf20Sopenharmony_ci		return -ENOMEM;
9898c2ecf20Sopenharmony_ci	sachip->saved_state = save;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	/*
9948c2ecf20Sopenharmony_ci	 * Save state.
9958c2ecf20Sopenharmony_ci	 */
9968c2ecf20Sopenharmony_ci	base = sachip->base;
9978c2ecf20Sopenharmony_ci	save->skcr     = readl_relaxed(base + SA1111_SKCR);
9988c2ecf20Sopenharmony_ci	save->skpcr    = readl_relaxed(base + SA1111_SKPCR);
9998c2ecf20Sopenharmony_ci	save->skcdr    = readl_relaxed(base + SA1111_SKCDR);
10008c2ecf20Sopenharmony_ci	save->skaud    = readl_relaxed(base + SA1111_SKAUD);
10018c2ecf20Sopenharmony_ci	save->skpwm0   = readl_relaxed(base + SA1111_SKPWM0);
10028c2ecf20Sopenharmony_ci	save->skpwm1   = readl_relaxed(base + SA1111_SKPWM1);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	writel_relaxed(0, sachip->base + SA1111_SKPWM0);
10058c2ecf20Sopenharmony_ci	writel_relaxed(0, sachip->base + SA1111_SKPWM1);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	base = sachip->base + SA1111_INTC;
10088c2ecf20Sopenharmony_ci	save->intpol0  = readl_relaxed(base + SA1111_INTPOL0);
10098c2ecf20Sopenharmony_ci	save->intpol1  = readl_relaxed(base + SA1111_INTPOL1);
10108c2ecf20Sopenharmony_ci	save->inten0   = readl_relaxed(base + SA1111_INTEN0);
10118c2ecf20Sopenharmony_ci	save->inten1   = readl_relaxed(base + SA1111_INTEN1);
10128c2ecf20Sopenharmony_ci	save->wakepol0 = readl_relaxed(base + SA1111_WAKEPOL0);
10138c2ecf20Sopenharmony_ci	save->wakepol1 = readl_relaxed(base + SA1111_WAKEPOL1);
10148c2ecf20Sopenharmony_ci	save->wakeen0  = readl_relaxed(base + SA1111_WAKEEN0);
10158c2ecf20Sopenharmony_ci	save->wakeen1  = readl_relaxed(base + SA1111_WAKEEN1);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/*
10188c2ecf20Sopenharmony_ci	 * Disable.
10198c2ecf20Sopenharmony_ci	 */
10208c2ecf20Sopenharmony_ci	val = readl_relaxed(sachip->base + SA1111_SKCR);
10218c2ecf20Sopenharmony_ci	writel_relaxed(val | SKCR_SLEEP, sachip->base + SA1111_SKCR);
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	clk_disable(sachip->clk);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_SA1100
10288c2ecf20Sopenharmony_ci	sa1110_mb_disable();
10298c2ecf20Sopenharmony_ci#endif
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	return 0;
10328c2ecf20Sopenharmony_ci}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci/*
10358c2ecf20Sopenharmony_ci *	sa1111_resume - Restore the SA1111 device state.
10368c2ecf20Sopenharmony_ci *	@dev: device to restore
10378c2ecf20Sopenharmony_ci *
10388c2ecf20Sopenharmony_ci *	Restore the general state of the SA1111; clock control and
10398c2ecf20Sopenharmony_ci *	interrupt controller.  Other parts of the SA1111 must be
10408c2ecf20Sopenharmony_ci *	restored by their respective drivers, and must be called
10418c2ecf20Sopenharmony_ci *	via LDM after this function.
10428c2ecf20Sopenharmony_ci */
10438c2ecf20Sopenharmony_cistatic int sa1111_resume_noirq(struct device *dev)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	struct sa1111 *sachip = dev_get_drvdata(dev);
10468c2ecf20Sopenharmony_ci	struct sa1111_save_data *save;
10478c2ecf20Sopenharmony_ci	unsigned long flags, id;
10488c2ecf20Sopenharmony_ci	void __iomem *base;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	save = sachip->saved_state;
10518c2ecf20Sopenharmony_ci	if (!save)
10528c2ecf20Sopenharmony_ci		return 0;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	/*
10558c2ecf20Sopenharmony_ci	 * Ensure that the SA1111 is still here.
10568c2ecf20Sopenharmony_ci	 * FIXME: shouldn't do this here.
10578c2ecf20Sopenharmony_ci	 */
10588c2ecf20Sopenharmony_ci	id = readl_relaxed(sachip->base + SA1111_SKID);
10598c2ecf20Sopenharmony_ci	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
10608c2ecf20Sopenharmony_ci		__sa1111_remove(sachip);
10618c2ecf20Sopenharmony_ci		dev_set_drvdata(dev, NULL);
10628c2ecf20Sopenharmony_ci		kfree(save);
10638c2ecf20Sopenharmony_ci		return 0;
10648c2ecf20Sopenharmony_ci	}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	/*
10678c2ecf20Sopenharmony_ci	 * First of all, wake up the chip.
10688c2ecf20Sopenharmony_ci	 */
10698c2ecf20Sopenharmony_ci	sa1111_wake(sachip);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_SA1100
10728c2ecf20Sopenharmony_ci	/* Enable the memory bus request/grant signals */
10738c2ecf20Sopenharmony_ci	sa1110_mb_enable();
10748c2ecf20Sopenharmony_ci#endif
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	/*
10778c2ecf20Sopenharmony_ci	 * Only lock for write ops. Also, sa1111_wake must be called with
10788c2ecf20Sopenharmony_ci	 * released spinlock!
10798c2ecf20Sopenharmony_ci	 */
10808c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	writel_relaxed(0, sachip->base + SA1111_INTC + SA1111_INTEN0);
10838c2ecf20Sopenharmony_ci	writel_relaxed(0, sachip->base + SA1111_INTC + SA1111_INTEN1);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	base = sachip->base;
10868c2ecf20Sopenharmony_ci	writel_relaxed(save->skcr,     base + SA1111_SKCR);
10878c2ecf20Sopenharmony_ci	writel_relaxed(save->skpcr,    base + SA1111_SKPCR);
10888c2ecf20Sopenharmony_ci	writel_relaxed(save->skcdr,    base + SA1111_SKCDR);
10898c2ecf20Sopenharmony_ci	writel_relaxed(save->skaud,    base + SA1111_SKAUD);
10908c2ecf20Sopenharmony_ci	writel_relaxed(save->skpwm0,   base + SA1111_SKPWM0);
10918c2ecf20Sopenharmony_ci	writel_relaxed(save->skpwm1,   base + SA1111_SKPWM1);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	base = sachip->base + SA1111_INTC;
10948c2ecf20Sopenharmony_ci	writel_relaxed(save->intpol0,  base + SA1111_INTPOL0);
10958c2ecf20Sopenharmony_ci	writel_relaxed(save->intpol1,  base + SA1111_INTPOL1);
10968c2ecf20Sopenharmony_ci	writel_relaxed(save->inten0,   base + SA1111_INTEN0);
10978c2ecf20Sopenharmony_ci	writel_relaxed(save->inten1,   base + SA1111_INTEN1);
10988c2ecf20Sopenharmony_ci	writel_relaxed(save->wakepol0, base + SA1111_WAKEPOL0);
10998c2ecf20Sopenharmony_ci	writel_relaxed(save->wakepol1, base + SA1111_WAKEPOL1);
11008c2ecf20Sopenharmony_ci	writel_relaxed(save->wakeen0,  base + SA1111_WAKEEN0);
11018c2ecf20Sopenharmony_ci	writel_relaxed(save->wakeen1,  base + SA1111_WAKEEN1);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	sachip->saved_state = NULL;
11068c2ecf20Sopenharmony_ci	kfree(save);
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	return 0;
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci#else
11128c2ecf20Sopenharmony_ci#define sa1111_suspend_noirq NULL
11138c2ecf20Sopenharmony_ci#define sa1111_resume_noirq  NULL
11148c2ecf20Sopenharmony_ci#endif
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_cistatic int sa1111_probe(struct platform_device *pdev)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	struct resource *mem;
11198c2ecf20Sopenharmony_ci	int irq;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
11228c2ecf20Sopenharmony_ci	if (!mem)
11238c2ecf20Sopenharmony_ci		return -EINVAL;
11248c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
11258c2ecf20Sopenharmony_ci	if (irq < 0)
11268c2ecf20Sopenharmony_ci		return irq;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	return __sa1111_probe(&pdev->dev, mem, irq);
11298c2ecf20Sopenharmony_ci}
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_cistatic int sa1111_remove(struct platform_device *pdev)
11328c2ecf20Sopenharmony_ci{
11338c2ecf20Sopenharmony_ci	struct sa1111 *sachip = platform_get_drvdata(pdev);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (sachip) {
11368c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
11378c2ecf20Sopenharmony_ci		kfree(sachip->saved_state);
11388c2ecf20Sopenharmony_ci		sachip->saved_state = NULL;
11398c2ecf20Sopenharmony_ci#endif
11408c2ecf20Sopenharmony_ci		__sa1111_remove(sachip);
11418c2ecf20Sopenharmony_ci		platform_set_drvdata(pdev, NULL);
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	return 0;
11458c2ecf20Sopenharmony_ci}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_cistatic struct dev_pm_ops sa1111_pm_ops = {
11488c2ecf20Sopenharmony_ci	.suspend_noirq = sa1111_suspend_noirq,
11498c2ecf20Sopenharmony_ci	.resume_noirq = sa1111_resume_noirq,
11508c2ecf20Sopenharmony_ci};
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci/*
11538c2ecf20Sopenharmony_ci *	Not sure if this should be on the system bus or not yet.
11548c2ecf20Sopenharmony_ci *	We really want some way to register a system device at
11558c2ecf20Sopenharmony_ci *	the per-machine level, and then have this driver pick
11568c2ecf20Sopenharmony_ci *	up the registered devices.
11578c2ecf20Sopenharmony_ci *
11588c2ecf20Sopenharmony_ci *	We also need to handle the SDRAM configuration for
11598c2ecf20Sopenharmony_ci *	PXA250/SA1110 machine classes.
11608c2ecf20Sopenharmony_ci */
11618c2ecf20Sopenharmony_cistatic struct platform_driver sa1111_device_driver = {
11628c2ecf20Sopenharmony_ci	.probe		= sa1111_probe,
11638c2ecf20Sopenharmony_ci	.remove		= sa1111_remove,
11648c2ecf20Sopenharmony_ci	.driver		= {
11658c2ecf20Sopenharmony_ci		.name	= "sa1111",
11668c2ecf20Sopenharmony_ci		.pm	= &sa1111_pm_ops,
11678c2ecf20Sopenharmony_ci	},
11688c2ecf20Sopenharmony_ci};
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci/*
11718c2ecf20Sopenharmony_ci *	Get the parent device driver (us) structure
11728c2ecf20Sopenharmony_ci *	from a child function device
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_cistatic inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent);
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci/*
11808c2ecf20Sopenharmony_ci * The bits in the opdiv field are non-linear.
11818c2ecf20Sopenharmony_ci */
11828c2ecf20Sopenharmony_cistatic unsigned char opdiv_table[] = { 1, 4, 2, 8 };
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic unsigned int __sa1111_pll_clock(struct sa1111 *sachip)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	unsigned int skcdr, fbdiv, ipdiv, opdiv;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	skcdr = readl_relaxed(sachip->base + SA1111_SKCDR);
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	fbdiv = (skcdr & 0x007f) + 2;
11918c2ecf20Sopenharmony_ci	ipdiv = ((skcdr & 0x0f80) >> 7) + 2;
11928c2ecf20Sopenharmony_ci	opdiv = opdiv_table[(skcdr & 0x3000) >> 12];
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	return 3686400 * fbdiv / (ipdiv * opdiv);
11958c2ecf20Sopenharmony_ci}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci/**
11988c2ecf20Sopenharmony_ci *	sa1111_pll_clock - return the current PLL clock frequency.
11998c2ecf20Sopenharmony_ci *	@sadev: SA1111 function block
12008c2ecf20Sopenharmony_ci *
12018c2ecf20Sopenharmony_ci *	BUG: we should look at SKCR.  We also blindly believe that
12028c2ecf20Sopenharmony_ci *	the chip is being fed with the 3.6864MHz clock.
12038c2ecf20Sopenharmony_ci *
12048c2ecf20Sopenharmony_ci *	Returns the PLL clock in Hz.
12058c2ecf20Sopenharmony_ci */
12068c2ecf20Sopenharmony_ciunsigned int sa1111_pll_clock(struct sa1111_dev *sadev)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	return __sa1111_pll_clock(sachip);
12118c2ecf20Sopenharmony_ci}
12128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_pll_clock);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci/**
12158c2ecf20Sopenharmony_ci *	sa1111_select_audio_mode - select I2S or AC link mode
12168c2ecf20Sopenharmony_ci *	@sadev: SA1111 function block
12178c2ecf20Sopenharmony_ci *	@mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S
12188c2ecf20Sopenharmony_ci *
12198c2ecf20Sopenharmony_ci *	Frob the SKCR to select AC Link mode or I2S mode for
12208c2ecf20Sopenharmony_ci *	the audio block.
12218c2ecf20Sopenharmony_ci */
12228c2ecf20Sopenharmony_civoid sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
12258c2ecf20Sopenharmony_ci	unsigned long flags;
12268c2ecf20Sopenharmony_ci	unsigned int val;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	val = readl_relaxed(sachip->base + SA1111_SKCR);
12318c2ecf20Sopenharmony_ci	if (mode == SA1111_AUDIO_I2S) {
12328c2ecf20Sopenharmony_ci		val &= ~SKCR_SELAC;
12338c2ecf20Sopenharmony_ci	} else {
12348c2ecf20Sopenharmony_ci		val |= SKCR_SELAC;
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci	writel_relaxed(val, sachip->base + SA1111_SKCR);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_select_audio_mode);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci/**
12438c2ecf20Sopenharmony_ci *	sa1111_set_audio_rate - set the audio sample rate
12448c2ecf20Sopenharmony_ci *	@sadev: SA1111 SAC function block
12458c2ecf20Sopenharmony_ci *	@rate: sample rate to select
12468c2ecf20Sopenharmony_ci */
12478c2ecf20Sopenharmony_ciint sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
12508c2ecf20Sopenharmony_ci	unsigned int div;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	if (sadev->devid != SA1111_DEVID_SAC)
12538c2ecf20Sopenharmony_ci		return -EINVAL;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate;
12568c2ecf20Sopenharmony_ci	if (div == 0)
12578c2ecf20Sopenharmony_ci		div = 1;
12588c2ecf20Sopenharmony_ci	if (div > 128)
12598c2ecf20Sopenharmony_ci		div = 128;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	writel_relaxed(div - 1, sachip->base + SA1111_SKAUD);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return 0;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_set_audio_rate);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci/**
12688c2ecf20Sopenharmony_ci *	sa1111_get_audio_rate - get the audio sample rate
12698c2ecf20Sopenharmony_ci *	@sadev: SA1111 SAC function block device
12708c2ecf20Sopenharmony_ci */
12718c2ecf20Sopenharmony_ciint sa1111_get_audio_rate(struct sa1111_dev *sadev)
12728c2ecf20Sopenharmony_ci{
12738c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
12748c2ecf20Sopenharmony_ci	unsigned long div;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (sadev->devid != SA1111_DEVID_SAC)
12778c2ecf20Sopenharmony_ci		return -EINVAL;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	div = readl_relaxed(sachip->base + SA1111_SKAUD) + 1;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	return __sa1111_pll_clock(sachip) / (256 * div);
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_get_audio_rate);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci/*
12868c2ecf20Sopenharmony_ci * Individual device operations.
12878c2ecf20Sopenharmony_ci */
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci/**
12908c2ecf20Sopenharmony_ci *	sa1111_enable_device - enable an on-chip SA1111 function block
12918c2ecf20Sopenharmony_ci *	@sadev: SA1111 function block device to enable
12928c2ecf20Sopenharmony_ci */
12938c2ecf20Sopenharmony_ciint sa1111_enable_device(struct sa1111_dev *sadev)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
12968c2ecf20Sopenharmony_ci	unsigned long flags;
12978c2ecf20Sopenharmony_ci	unsigned int val;
12988c2ecf20Sopenharmony_ci	int ret = 0;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (sachip->pdata && sachip->pdata->enable)
13018c2ecf20Sopenharmony_ci		ret = sachip->pdata->enable(sachip->pdata->data, sadev->devid);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (ret == 0) {
13048c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sachip->lock, flags);
13058c2ecf20Sopenharmony_ci		val = readl_relaxed(sachip->base + SA1111_SKPCR);
13068c2ecf20Sopenharmony_ci		writel_relaxed(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
13078c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sachip->lock, flags);
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci	return ret;
13108c2ecf20Sopenharmony_ci}
13118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_enable_device);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci/**
13148c2ecf20Sopenharmony_ci *	sa1111_disable_device - disable an on-chip SA1111 function block
13158c2ecf20Sopenharmony_ci *	@sadev: SA1111 function block device to disable
13168c2ecf20Sopenharmony_ci */
13178c2ecf20Sopenharmony_civoid sa1111_disable_device(struct sa1111_dev *sadev)
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
13208c2ecf20Sopenharmony_ci	unsigned long flags;
13218c2ecf20Sopenharmony_ci	unsigned int val;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sachip->lock, flags);
13248c2ecf20Sopenharmony_ci	val = readl_relaxed(sachip->base + SA1111_SKPCR);
13258c2ecf20Sopenharmony_ci	writel_relaxed(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
13268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sachip->lock, flags);
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	if (sachip->pdata && sachip->pdata->disable)
13298c2ecf20Sopenharmony_ci		sachip->pdata->disable(sachip->pdata->data, sadev->devid);
13308c2ecf20Sopenharmony_ci}
13318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_disable_device);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ciint sa1111_get_irq(struct sa1111_dev *sadev, unsigned num)
13348c2ecf20Sopenharmony_ci{
13358c2ecf20Sopenharmony_ci	struct sa1111 *sachip = sa1111_chip_driver(sadev);
13368c2ecf20Sopenharmony_ci	if (num >= ARRAY_SIZE(sadev->hwirq))
13378c2ecf20Sopenharmony_ci		return -EINVAL;
13388c2ecf20Sopenharmony_ci	return sa1111_map_irq(sachip, sadev->hwirq[num]);
13398c2ecf20Sopenharmony_ci}
13408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sa1111_get_irq);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci/*
13438c2ecf20Sopenharmony_ci *	SA1111 "Register Access Bus."
13448c2ecf20Sopenharmony_ci *
13458c2ecf20Sopenharmony_ci *	We model this as a regular bus type, and hang devices directly
13468c2ecf20Sopenharmony_ci *	off this.
13478c2ecf20Sopenharmony_ci */
13488c2ecf20Sopenharmony_cistatic int sa1111_match(struct device *_dev, struct device_driver *_drv)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	struct sa1111_dev *dev = to_sa1111_device(_dev);
13518c2ecf20Sopenharmony_ci	struct sa1111_driver *drv = SA1111_DRV(_drv);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	return !!(dev->devid & drv->devid);
13548c2ecf20Sopenharmony_ci}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_cistatic int sa1111_bus_probe(struct device *dev)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	struct sa1111_dev *sadev = to_sa1111_device(dev);
13598c2ecf20Sopenharmony_ci	struct sa1111_driver *drv = SA1111_DRV(dev->driver);
13608c2ecf20Sopenharmony_ci	int ret = -ENODEV;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	if (drv->probe)
13638c2ecf20Sopenharmony_ci		ret = drv->probe(sadev);
13648c2ecf20Sopenharmony_ci	return ret;
13658c2ecf20Sopenharmony_ci}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_cistatic int sa1111_bus_remove(struct device *dev)
13688c2ecf20Sopenharmony_ci{
13698c2ecf20Sopenharmony_ci	struct sa1111_dev *sadev = to_sa1111_device(dev);
13708c2ecf20Sopenharmony_ci	struct sa1111_driver *drv = SA1111_DRV(dev->driver);
13718c2ecf20Sopenharmony_ci	int ret = 0;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	if (drv->remove)
13748c2ecf20Sopenharmony_ci		ret = drv->remove(sadev);
13758c2ecf20Sopenharmony_ci	return ret;
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_cistruct bus_type sa1111_bus_type = {
13798c2ecf20Sopenharmony_ci	.name		= "sa1111-rab",
13808c2ecf20Sopenharmony_ci	.match		= sa1111_match,
13818c2ecf20Sopenharmony_ci	.probe		= sa1111_bus_probe,
13828c2ecf20Sopenharmony_ci	.remove		= sa1111_bus_remove,
13838c2ecf20Sopenharmony_ci};
13848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_bus_type);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ciint sa1111_driver_register(struct sa1111_driver *driver)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	driver->drv.bus = &sa1111_bus_type;
13898c2ecf20Sopenharmony_ci	return driver_register(&driver->drv);
13908c2ecf20Sopenharmony_ci}
13918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_driver_register);
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_civoid sa1111_driver_unregister(struct sa1111_driver *driver)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	driver_unregister(&driver->drv);
13968c2ecf20Sopenharmony_ci}
13978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sa1111_driver_unregister);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci#ifdef CONFIG_DMABOUNCE
14008c2ecf20Sopenharmony_ci/*
14018c2ecf20Sopenharmony_ci * According to the "Intel StrongARM SA-1111 Microprocessor Companion
14028c2ecf20Sopenharmony_ci * Chip Specification Update" (June 2000), erratum #7, there is a
14038c2ecf20Sopenharmony_ci * significant bug in the SA1111 SDRAM shared memory controller.  If
14048c2ecf20Sopenharmony_ci * an access to a region of memory above 1MB relative to the bank base,
14058c2ecf20Sopenharmony_ci * it is important that address bit 10 _NOT_ be asserted. Depending
14068c2ecf20Sopenharmony_ci * on the configuration of the RAM, bit 10 may correspond to one
14078c2ecf20Sopenharmony_ci * of several different (processor-relative) address bits.
14088c2ecf20Sopenharmony_ci *
14098c2ecf20Sopenharmony_ci * This routine only identifies whether or not a given DMA address
14108c2ecf20Sopenharmony_ci * is susceptible to the bug.
14118c2ecf20Sopenharmony_ci *
14128c2ecf20Sopenharmony_ci * This should only get called for sa1111_device types due to the
14138c2ecf20Sopenharmony_ci * way we configure our device dma_masks.
14148c2ecf20Sopenharmony_ci */
14158c2ecf20Sopenharmony_cistatic int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	/*
14188c2ecf20Sopenharmony_ci	 * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
14198c2ecf20Sopenharmony_ci	 * User's Guide" mentions that jumpers R51 and R52 control the
14208c2ecf20Sopenharmony_ci	 * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
14218c2ecf20Sopenharmony_ci	 * SDRAM bank 1 on Neponset). The default configuration selects
14228c2ecf20Sopenharmony_ci	 * Assabet, so any address in bank 1 is necessarily invalid.
14238c2ecf20Sopenharmony_ci	 */
14248c2ecf20Sopenharmony_ci	return (machine_is_assabet() || machine_is_pfs168()) &&
14258c2ecf20Sopenharmony_ci		(addr >= 0xc8000000 || (addr + size) >= 0xc8000000);
14268c2ecf20Sopenharmony_ci}
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_cistatic int sa1111_notifier_call(struct notifier_block *n, unsigned long action,
14298c2ecf20Sopenharmony_ci	void *data)
14308c2ecf20Sopenharmony_ci{
14318c2ecf20Sopenharmony_ci	struct sa1111_dev *dev = to_sa1111_device(data);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	switch (action) {
14348c2ecf20Sopenharmony_ci	case BUS_NOTIFY_ADD_DEVICE:
14358c2ecf20Sopenharmony_ci		if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL) {
14368c2ecf20Sopenharmony_ci			int ret = dmabounce_register_dev(&dev->dev, 1024, 4096,
14378c2ecf20Sopenharmony_ci					sa1111_needs_bounce);
14388c2ecf20Sopenharmony_ci			if (ret)
14398c2ecf20Sopenharmony_ci				dev_err(&dev->dev, "failed to register with dmabounce: %d\n", ret);
14408c2ecf20Sopenharmony_ci		}
14418c2ecf20Sopenharmony_ci		break;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	case BUS_NOTIFY_DEL_DEVICE:
14448c2ecf20Sopenharmony_ci		if (dev->dev.dma_mask && dev->dma_mask < 0xffffffffUL)
14458c2ecf20Sopenharmony_ci			dmabounce_unregister_dev(&dev->dev);
14468c2ecf20Sopenharmony_ci		break;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci	return NOTIFY_OK;
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic struct notifier_block sa1111_bus_notifier = {
14528c2ecf20Sopenharmony_ci	.notifier_call = sa1111_notifier_call,
14538c2ecf20Sopenharmony_ci};
14548c2ecf20Sopenharmony_ci#endif
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic int __init sa1111_init(void)
14578c2ecf20Sopenharmony_ci{
14588c2ecf20Sopenharmony_ci	int ret = bus_register(&sa1111_bus_type);
14598c2ecf20Sopenharmony_ci#ifdef CONFIG_DMABOUNCE
14608c2ecf20Sopenharmony_ci	if (ret == 0)
14618c2ecf20Sopenharmony_ci		bus_register_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
14628c2ecf20Sopenharmony_ci#endif
14638c2ecf20Sopenharmony_ci	if (ret == 0)
14648c2ecf20Sopenharmony_ci		platform_driver_register(&sa1111_device_driver);
14658c2ecf20Sopenharmony_ci	return ret;
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_cistatic void __exit sa1111_exit(void)
14698c2ecf20Sopenharmony_ci{
14708c2ecf20Sopenharmony_ci	platform_driver_unregister(&sa1111_device_driver);
14718c2ecf20Sopenharmony_ci#ifdef CONFIG_DMABOUNCE
14728c2ecf20Sopenharmony_ci	bus_unregister_notifier(&sa1111_bus_type, &sa1111_bus_notifier);
14738c2ecf20Sopenharmony_ci#endif
14748c2ecf20Sopenharmony_ci	bus_unregister(&sa1111_bus_type);
14758c2ecf20Sopenharmony_ci}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_cisubsys_initcall(sa1111_init);
14788c2ecf20Sopenharmony_cimodule_exit(sa1111_exit);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Corporation SA1111 core driver");
14818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1482