11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    bttv-gpio.c  --  gpio sub drivers
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    sysfs-based sub driver interface for bttv
625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi    mainly intended for gpio access
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
104ac97914c6c35f6bf132071c718e034d0846b9f5Mauro Carvalho Chehab			   & Marcus Metzler (mocm@thp.uni-koeln.de)
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
298af443e581ab57a6a38f595eb40be3514ea55195Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
308af443e581ab57a6a38f595eb40be3514ea55195Joe Perches
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
355a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "bttvp.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ----------------------------------------------------------------------- */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* internal: the bttv "bus"                                                */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = strlen(sub->wanted);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48af128a102c4aee994b4ff6e422b3cfab17127578Kay Sievers	if (0 == strncmp(dev_name(dev), sub->wanted, len))
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53348290a4ae143a692124330942b464ccdb0d0365Russell Kingstatic int bttv_sub_probe(struct device *dev)
54348290a4ae143a692124330942b464ccdb0d0365Russell King{
55348290a4ae143a692124330942b464ccdb0d0365Russell King	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
56348290a4ae143a692124330942b464ccdb0d0365Russell King	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
57348290a4ae143a692124330942b464ccdb0d0365Russell King
58348290a4ae143a692124330942b464ccdb0d0365Russell King	return sub->probe ? sub->probe(sdev) : -ENODEV;
59348290a4ae143a692124330942b464ccdb0d0365Russell King}
60348290a4ae143a692124330942b464ccdb0d0365Russell King
61348290a4ae143a692124330942b464ccdb0d0365Russell Kingstatic int bttv_sub_remove(struct device *dev)
62348290a4ae143a692124330942b464ccdb0d0365Russell King{
63348290a4ae143a692124330942b464ccdb0d0365Russell King	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
64348290a4ae143a692124330942b464ccdb0d0365Russell King	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
65348290a4ae143a692124330942b464ccdb0d0365Russell King
66348290a4ae143a692124330942b464ccdb0d0365Russell King	if (sub->remove)
67348290a4ae143a692124330942b464ccdb0d0365Russell King		sub->remove(sdev);
68348290a4ae143a692124330942b464ccdb0d0365Russell King	return 0;
69348290a4ae143a692124330942b464ccdb0d0365Russell King}
70348290a4ae143a692124330942b464ccdb0d0365Russell King
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bus_type bttv_sub_bus_type = {
72348290a4ae143a692124330942b464ccdb0d0365Russell King	.name   = "bttv-sub",
73348290a4ae143a692124330942b464ccdb0d0365Russell King	.match  = &bttv_sub_bus_match,
74348290a4ae143a692124330942b464ccdb0d0365Russell King	.probe  = bttv_sub_probe,
75348290a4ae143a692124330942b464ccdb0d0365Russell King	.remove = bttv_sub_remove,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void release_sub_device(struct device *dev)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(sub);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bttv_sub_add_device(struct bttv_core *core, char *name)
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv_sub_device *sub;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
897408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris	sub = kzalloc(sizeof(*sub),GFP_KERNEL);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (NULL == sub)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sub->core        = core;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sub->dev.parent  = &core->pci->dev;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sub->dev.bus     = &bttv_sub_bus_type;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sub->dev.release = release_sub_device;
97af128a102c4aee994b4ff6e422b3cfab17127578Kay Sievers	dev_set_name(&sub->dev, "%s%d", name, core->nr);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = device_register(&sub->dev);
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0 != err) {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(sub);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1048af443e581ab57a6a38f595eb40be3514ea55195Joe Perches	pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&sub->list,&core->subs);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bttv_sub_del_devices(struct bttv_core *core)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
111a991f44b79fa49b281eb078eed4a76a42101012aTrent Piepho	struct bttv_sub_device *sub, *save;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
113a991f44b79fa49b281eb078eed4a76a42101012aTrent Piepho	list_for_each_entry_safe(sub, save, &core->subs, list) {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_del(&sub->list);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device_unregister(&sub->dev);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ----------------------------------------------------------------------- */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* external: sub-driver register/unregister                                */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sub->drv.bus = &bttv_sub_bus_type;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return driver_register(&sub->drv);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bttv_sub_register);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bttv_sub_unregister(struct bttv_sub_driver *sub)
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	driver_unregister(&sub->drv);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bttv_sub_unregister);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ----------------------------------------------------------------------- */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* external: gpio access functions                                         */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv *btv = container_of(core, struct bttv, c);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 data;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&btv->gpio_lock,flags);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = btread(BT848_GPIO_OUT_EN);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = data & ~mask;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = data | (mask & outbits);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	btwrite(data,BT848_GPIO_OUT_EN);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&btv->gpio_lock,flags);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu32 bttv_gpio_read(struct bttv_core *core)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv *btv = container_of(core, struct bttv, c);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 value;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = btread(BT848_GPIO_DATA);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return value;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bttv_gpio_write(struct bttv_core *core, u32 value)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv *btv = container_of(core, struct bttv, c);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	btwrite(value,BT848_GPIO_DATA);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bttv *btv = container_of(core, struct bttv, c);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 data;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&btv->gpio_lock,flags);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = btread(BT848_GPIO_DATA);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = data & ~mask;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = data | (mask & bits);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	btwrite(data,BT848_GPIO_DATA);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&btv->gpio_lock,flags);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Local variables:
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * c-basic-offset: 8
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End:
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
190