Linux Audio

Check our new training course

In-person Linux kernel drivers training

Jun 16-20, 2025
Register
Loading...
v3.15
  1/*
  2 * Support code for the SCOOP interface found on various Sharp PDAs
  3 *
  4 * Copyright (c) 2004 Richard Purdie
  5 *
  6 *	Based on code written by Sharp/Lineo for 2.4 kernels
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License version 2 as
 10 * published by the Free Software Foundation.
 11 *
 12 */
 13
 14#include <linux/device.h>
 15#include <linux/gpio.h>
 16#include <linux/string.h>
 17#include <linux/slab.h>
 18#include <linux/platform_device.h>
 19#include <linux/export.h>
 20#include <linux/io.h>
 21#include <asm/hardware/scoop.h>
 22
 23/* PCMCIA to Scoop linkage
 24
 25   There is no easy way to link multiple scoop devices into one
 26   single entity for the pxa2xx_pcmcia device so this structure
 27   is used which is setup by the platform code.
 28
 29   This file is never modular so this symbol is always
 30   accessile to the board support files.
 31*/
 32struct scoop_pcmcia_config *platform_scoop_config;
 33EXPORT_SYMBOL(platform_scoop_config);
 34
 35struct  scoop_dev {
 36	void __iomem *base;
 37	struct gpio_chip gpio;
 38	spinlock_t scoop_lock;
 39	unsigned short suspend_clr;
 40	unsigned short suspend_set;
 41	u32 scoop_gpwr;
 42};
 43
 44void reset_scoop(struct device *dev)
 45{
 46	struct scoop_dev *sdev = dev_get_drvdata(dev);
 47
 48	iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
 49	iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
 50	iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
 51	iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
 52	iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
 53	iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
 54	iowrite16(0x0000, sdev->base + SCOOP_IRM);
 55}
 56
 57static void __scoop_gpio_set(struct scoop_dev *sdev,
 58			unsigned offset, int value)
 59{
 60	unsigned short gpwr;
 61
 62	gpwr = ioread16(sdev->base + SCOOP_GPWR);
 63	if (value)
 64		gpwr |= 1 << (offset + 1);
 65	else
 66		gpwr &= ~(1 << (offset + 1));
 67	iowrite16(gpwr, sdev->base + SCOOP_GPWR);
 68}
 69
 70static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 71{
 72	struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
 73	unsigned long flags;
 74
 75	spin_lock_irqsave(&sdev->scoop_lock, flags);
 76
 77	__scoop_gpio_set(sdev, offset, value);
 78
 79	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 80}
 81
 82static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
 83{
 84	struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
 85
 86	/* XXX: I'm unsure, but it seems so */
 87	return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
 88}
 89
 90static int scoop_gpio_direction_input(struct gpio_chip *chip,
 91			unsigned offset)
 92{
 93	struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
 94	unsigned long flags;
 95	unsigned short gpcr;
 96
 97	spin_lock_irqsave(&sdev->scoop_lock, flags);
 98
 99	gpcr = ioread16(sdev->base + SCOOP_GPCR);
100	gpcr &= ~(1 << (offset + 1));
101	iowrite16(gpcr, sdev->base + SCOOP_GPCR);
102
103	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
104
105	return 0;
106}
107
108static int scoop_gpio_direction_output(struct gpio_chip *chip,
109			unsigned offset, int value)
110{
111	struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
112	unsigned long flags;
113	unsigned short gpcr;
114
115	spin_lock_irqsave(&sdev->scoop_lock, flags);
116
117	__scoop_gpio_set(sdev, offset, value);
118
119	gpcr = ioread16(sdev->base + SCOOP_GPCR);
120	gpcr |= 1 << (offset + 1);
121	iowrite16(gpcr, sdev->base + SCOOP_GPCR);
122
123	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
124
125	return 0;
126}
127
128unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
129{
130	struct scoop_dev *sdev = dev_get_drvdata(dev);
131	return ioread16(sdev->base + reg);
132}
133
134void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
135{
136	struct scoop_dev *sdev = dev_get_drvdata(dev);
137	iowrite16(data, sdev->base + reg);
138}
139
140EXPORT_SYMBOL(reset_scoop);
141EXPORT_SYMBOL(read_scoop_reg);
142EXPORT_SYMBOL(write_scoop_reg);
143
144#ifdef CONFIG_PM
145static void check_scoop_reg(struct scoop_dev *sdev)
146{
147	unsigned short mcr;
148
149	mcr = ioread16(sdev->base + SCOOP_MCR);
150	if ((mcr & 0x100) == 0)
151		iowrite16(0x0101, sdev->base + SCOOP_MCR);
152}
153
154static int scoop_suspend(struct platform_device *dev, pm_message_t state)
155{
156	struct scoop_dev *sdev = platform_get_drvdata(dev);
157
158	check_scoop_reg(sdev);
159	sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
160	iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
161
162	return 0;
163}
164
165static int scoop_resume(struct platform_device *dev)
166{
167	struct scoop_dev *sdev = platform_get_drvdata(dev);
168
169	check_scoop_reg(sdev);
170	iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
171
172	return 0;
173}
174#else
175#define scoop_suspend	NULL
176#define scoop_resume	NULL
177#endif
178
179static int scoop_probe(struct platform_device *pdev)
180{
181	struct scoop_dev *devptr;
182	struct scoop_config *inf;
183	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
184	int ret;
185	int temp;
186
187	if (!mem)
188		return -EINVAL;
189
190	devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
191	if (!devptr)
192		return -ENOMEM;
193
194	spin_lock_init(&devptr->scoop_lock);
195
196	inf = pdev->dev.platform_data;
197	devptr->base = ioremap(mem->start, resource_size(mem));
198
199	if (!devptr->base) {
200		ret = -ENOMEM;
201		goto err_ioremap;
202	}
203
204	platform_set_drvdata(pdev, devptr);
205
206	printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
207
208	iowrite16(0x0140, devptr->base + SCOOP_MCR);
209	reset_scoop(&pdev->dev);
210	iowrite16(0x0000, devptr->base + SCOOP_CPR);
211	iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
212	iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
213
214	devptr->suspend_clr = inf->suspend_clr;
215	devptr->suspend_set = inf->suspend_set;
216
217	devptr->gpio.base = -1;
218
219	if (inf->gpio_base != 0) {
220		devptr->gpio.label = dev_name(&pdev->dev);
221		devptr->gpio.base = inf->gpio_base;
222		devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
223		devptr->gpio.set = scoop_gpio_set;
224		devptr->gpio.get = scoop_gpio_get;
225		devptr->gpio.direction_input = scoop_gpio_direction_input;
226		devptr->gpio.direction_output = scoop_gpio_direction_output;
227
228		ret = gpiochip_add(&devptr->gpio);
229		if (ret)
230			goto err_gpio;
231	}
232
233	return 0;
234
235err_gpio:
236	platform_set_drvdata(pdev, NULL);
237err_ioremap:
238	iounmap(devptr->base);
239	kfree(devptr);
240
241	return ret;
242}
243
244static int scoop_remove(struct platform_device *pdev)
245{
246	struct scoop_dev *sdev = platform_get_drvdata(pdev);
247	int ret;
248
249	if (!sdev)
250		return -EINVAL;
251
252	if (sdev->gpio.base != -1) {
253		ret = gpiochip_remove(&sdev->gpio);
254		if (ret) {
255			dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
256			return ret;
257		}
258	}
259
260	platform_set_drvdata(pdev, NULL);
261	iounmap(sdev->base);
262	kfree(sdev);
263
264	return 0;
265}
266
267static struct platform_driver scoop_driver = {
268	.probe		= scoop_probe,
269	.remove		= scoop_remove,
270	.suspend	= scoop_suspend,
271	.resume		= scoop_resume,
272	.driver		= {
273		.name	= "sharp-scoop",
274	},
275};
276
277static int __init scoop_init(void)
278{
279	return platform_driver_register(&scoop_driver);
280}
281
282subsys_initcall(scoop_init);
v4.17
  1/*
  2 * Support code for the SCOOP interface found on various Sharp PDAs
  3 *
  4 * Copyright (c) 2004 Richard Purdie
  5 *
  6 *	Based on code written by Sharp/Lineo for 2.4 kernels
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License version 2 as
 10 * published by the Free Software Foundation.
 11 *
 12 */
 13
 14#include <linux/device.h>
 15#include <linux/gpio.h>
 16#include <linux/string.h>
 17#include <linux/slab.h>
 18#include <linux/platform_device.h>
 19#include <linux/export.h>
 20#include <linux/io.h>
 21#include <asm/hardware/scoop.h>
 22
 23/* PCMCIA to Scoop linkage
 24
 25   There is no easy way to link multiple scoop devices into one
 26   single entity for the pxa2xx_pcmcia device so this structure
 27   is used which is setup by the platform code.
 28
 29   This file is never modular so this symbol is always
 30   accessile to the board support files.
 31*/
 32struct scoop_pcmcia_config *platform_scoop_config;
 33EXPORT_SYMBOL(platform_scoop_config);
 34
 35struct  scoop_dev {
 36	void __iomem *base;
 37	struct gpio_chip gpio;
 38	spinlock_t scoop_lock;
 39	unsigned short suspend_clr;
 40	unsigned short suspend_set;
 41	u32 scoop_gpwr;
 42};
 43
 44void reset_scoop(struct device *dev)
 45{
 46	struct scoop_dev *sdev = dev_get_drvdata(dev);
 47
 48	iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
 49	iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
 50	iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
 51	iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
 52	iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
 53	iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
 54	iowrite16(0x0000, sdev->base + SCOOP_IRM);
 55}
 56
 57static void __scoop_gpio_set(struct scoop_dev *sdev,
 58			unsigned offset, int value)
 59{
 60	unsigned short gpwr;
 61
 62	gpwr = ioread16(sdev->base + SCOOP_GPWR);
 63	if (value)
 64		gpwr |= 1 << (offset + 1);
 65	else
 66		gpwr &= ~(1 << (offset + 1));
 67	iowrite16(gpwr, sdev->base + SCOOP_GPWR);
 68}
 69
 70static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 71{
 72	struct scoop_dev *sdev = gpiochip_get_data(chip);
 73	unsigned long flags;
 74
 75	spin_lock_irqsave(&sdev->scoop_lock, flags);
 76
 77	__scoop_gpio_set(sdev, offset, value);
 78
 79	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 80}
 81
 82static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
 83{
 84	struct scoop_dev *sdev = gpiochip_get_data(chip);
 85
 86	/* XXX: I'm unsure, but it seems so */
 87	return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
 88}
 89
 90static int scoop_gpio_direction_input(struct gpio_chip *chip,
 91			unsigned offset)
 92{
 93	struct scoop_dev *sdev = gpiochip_get_data(chip);
 94	unsigned long flags;
 95	unsigned short gpcr;
 96
 97	spin_lock_irqsave(&sdev->scoop_lock, flags);
 98
 99	gpcr = ioread16(sdev->base + SCOOP_GPCR);
100	gpcr &= ~(1 << (offset + 1));
101	iowrite16(gpcr, sdev->base + SCOOP_GPCR);
102
103	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
104
105	return 0;
106}
107
108static int scoop_gpio_direction_output(struct gpio_chip *chip,
109			unsigned offset, int value)
110{
111	struct scoop_dev *sdev = gpiochip_get_data(chip);
112	unsigned long flags;
113	unsigned short gpcr;
114
115	spin_lock_irqsave(&sdev->scoop_lock, flags);
116
117	__scoop_gpio_set(sdev, offset, value);
118
119	gpcr = ioread16(sdev->base + SCOOP_GPCR);
120	gpcr |= 1 << (offset + 1);
121	iowrite16(gpcr, sdev->base + SCOOP_GPCR);
122
123	spin_unlock_irqrestore(&sdev->scoop_lock, flags);
124
125	return 0;
126}
127
128unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
129{
130	struct scoop_dev *sdev = dev_get_drvdata(dev);
131	return ioread16(sdev->base + reg);
132}
133
134void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
135{
136	struct scoop_dev *sdev = dev_get_drvdata(dev);
137	iowrite16(data, sdev->base + reg);
138}
139
140EXPORT_SYMBOL(reset_scoop);
141EXPORT_SYMBOL(read_scoop_reg);
142EXPORT_SYMBOL(write_scoop_reg);
143
144#ifdef CONFIG_PM
145static void check_scoop_reg(struct scoop_dev *sdev)
146{
147	unsigned short mcr;
148
149	mcr = ioread16(sdev->base + SCOOP_MCR);
150	if ((mcr & 0x100) == 0)
151		iowrite16(0x0101, sdev->base + SCOOP_MCR);
152}
153
154static int scoop_suspend(struct platform_device *dev, pm_message_t state)
155{
156	struct scoop_dev *sdev = platform_get_drvdata(dev);
157
158	check_scoop_reg(sdev);
159	sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
160	iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
161
162	return 0;
163}
164
165static int scoop_resume(struct platform_device *dev)
166{
167	struct scoop_dev *sdev = platform_get_drvdata(dev);
168
169	check_scoop_reg(sdev);
170	iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
171
172	return 0;
173}
174#else
175#define scoop_suspend	NULL
176#define scoop_resume	NULL
177#endif
178
179static int scoop_probe(struct platform_device *pdev)
180{
181	struct scoop_dev *devptr;
182	struct scoop_config *inf;
183	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
184	int ret;
 
185
186	if (!mem)
187		return -EINVAL;
188
189	devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
190	if (!devptr)
191		return -ENOMEM;
192
193	spin_lock_init(&devptr->scoop_lock);
194
195	inf = pdev->dev.platform_data;
196	devptr->base = ioremap(mem->start, resource_size(mem));
197
198	if (!devptr->base) {
199		ret = -ENOMEM;
200		goto err_ioremap;
201	}
202
203	platform_set_drvdata(pdev, devptr);
204
205	printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
206
207	iowrite16(0x0140, devptr->base + SCOOP_MCR);
208	reset_scoop(&pdev->dev);
209	iowrite16(0x0000, devptr->base + SCOOP_CPR);
210	iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
211	iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
212
213	devptr->suspend_clr = inf->suspend_clr;
214	devptr->suspend_set = inf->suspend_set;
215
216	devptr->gpio.base = -1;
217
218	if (inf->gpio_base != 0) {
219		devptr->gpio.label = dev_name(&pdev->dev);
220		devptr->gpio.base = inf->gpio_base;
221		devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
222		devptr->gpio.set = scoop_gpio_set;
223		devptr->gpio.get = scoop_gpio_get;
224		devptr->gpio.direction_input = scoop_gpio_direction_input;
225		devptr->gpio.direction_output = scoop_gpio_direction_output;
226
227		ret = gpiochip_add_data(&devptr->gpio, devptr);
228		if (ret)
229			goto err_gpio;
230	}
231
232	return 0;
233
234err_gpio:
235	platform_set_drvdata(pdev, NULL);
236err_ioremap:
237	iounmap(devptr->base);
238	kfree(devptr);
239
240	return ret;
241}
242
243static int scoop_remove(struct platform_device *pdev)
244{
245	struct scoop_dev *sdev = platform_get_drvdata(pdev);
 
246
247	if (!sdev)
248		return -EINVAL;
249
250	if (sdev->gpio.base != -1)
251		gpiochip_remove(&sdev->gpio);
 
 
 
 
 
252
253	platform_set_drvdata(pdev, NULL);
254	iounmap(sdev->base);
255	kfree(sdev);
256
257	return 0;
258}
259
260static struct platform_driver scoop_driver = {
261	.probe		= scoop_probe,
262	.remove		= scoop_remove,
263	.suspend	= scoop_suspend,
264	.resume		= scoop_resume,
265	.driver		= {
266		.name	= "sharp-scoop",
267	},
268};
269
270static int __init scoop_init(void)
271{
272	return platform_driver_register(&scoop_driver);
273}
274
275subsys_initcall(scoop_init);