174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
268de959fSMauro Carvalho Chehab /*
368de959fSMauro Carvalho Chehab 
468de959fSMauro Carvalho Chehab     bttv-gpio.c  --  gpio sub drivers
568de959fSMauro Carvalho Chehab 
668de959fSMauro Carvalho Chehab     sysfs-based sub driver interface for bttv
768de959fSMauro Carvalho Chehab     mainly intended for gpio access
868de959fSMauro Carvalho Chehab 
968de959fSMauro Carvalho Chehab 
1068de959fSMauro Carvalho Chehab     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
1168de959fSMauro Carvalho Chehab 			   & Marcus Metzler (mocm@thp.uni-koeln.de)
1268de959fSMauro Carvalho Chehab     (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
1368de959fSMauro Carvalho Chehab 
1468de959fSMauro Carvalho Chehab 
1568de959fSMauro Carvalho Chehab */
1668de959fSMauro Carvalho Chehab 
1768de959fSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1868de959fSMauro Carvalho Chehab 
1968de959fSMauro Carvalho Chehab #include <linux/module.h>
2068de959fSMauro Carvalho Chehab #include <linux/init.h>
2168de959fSMauro Carvalho Chehab #include <linux/delay.h>
2268de959fSMauro Carvalho Chehab #include <linux/device.h>
2368de959fSMauro Carvalho Chehab #include <linux/slab.h>
2468de959fSMauro Carvalho Chehab #include <asm/io.h>
2568de959fSMauro Carvalho Chehab 
2668de959fSMauro Carvalho Chehab #include "bttvp.h"
2768de959fSMauro Carvalho Chehab 
2868de959fSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
2968de959fSMauro Carvalho Chehab /* internal: the bttv "bus"                                                */
3068de959fSMauro Carvalho Chehab 
bttv_sub_bus_match(struct device * dev,struct device_driver * drv)3168de959fSMauro Carvalho Chehab static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
3268de959fSMauro Carvalho Chehab {
3368de959fSMauro Carvalho Chehab 	struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
3468de959fSMauro Carvalho Chehab 	int len = strlen(sub->wanted);
3568de959fSMauro Carvalho Chehab 
3668de959fSMauro Carvalho Chehab 	if (0 == strncmp(dev_name(dev), sub->wanted, len))
3768de959fSMauro Carvalho Chehab 		return 1;
3868de959fSMauro Carvalho Chehab 	return 0;
3968de959fSMauro Carvalho Chehab }
4068de959fSMauro Carvalho Chehab 
bttv_sub_probe(struct device * dev)4168de959fSMauro Carvalho Chehab static int bttv_sub_probe(struct device *dev)
4268de959fSMauro Carvalho Chehab {
4368de959fSMauro Carvalho Chehab 	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
4468de959fSMauro Carvalho Chehab 	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
4568de959fSMauro Carvalho Chehab 
4668de959fSMauro Carvalho Chehab 	return sub->probe ? sub->probe(sdev) : -ENODEV;
4768de959fSMauro Carvalho Chehab }
4868de959fSMauro Carvalho Chehab 
bttv_sub_remove(struct device * dev)49*fc7a6209SUwe Kleine-König static void bttv_sub_remove(struct device *dev)
5068de959fSMauro Carvalho Chehab {
5168de959fSMauro Carvalho Chehab 	struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
5268de959fSMauro Carvalho Chehab 	struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
5368de959fSMauro Carvalho Chehab 
5468de959fSMauro Carvalho Chehab 	if (sub->remove)
5568de959fSMauro Carvalho Chehab 		sub->remove(sdev);
5668de959fSMauro Carvalho Chehab }
5768de959fSMauro Carvalho Chehab 
5868de959fSMauro Carvalho Chehab struct bus_type bttv_sub_bus_type = {
5968de959fSMauro Carvalho Chehab 	.name   = "bttv-sub",
6068de959fSMauro Carvalho Chehab 	.match  = &bttv_sub_bus_match,
6168de959fSMauro Carvalho Chehab 	.probe  = bttv_sub_probe,
6268de959fSMauro Carvalho Chehab 	.remove = bttv_sub_remove,
6368de959fSMauro Carvalho Chehab };
6468de959fSMauro Carvalho Chehab 
release_sub_device(struct device * dev)6568de959fSMauro Carvalho Chehab static void release_sub_device(struct device *dev)
6668de959fSMauro Carvalho Chehab {
6768de959fSMauro Carvalho Chehab 	struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
6868de959fSMauro Carvalho Chehab 	kfree(sub);
6968de959fSMauro Carvalho Chehab }
7068de959fSMauro Carvalho Chehab 
bttv_sub_add_device(struct bttv_core * core,char * name)7168de959fSMauro Carvalho Chehab int bttv_sub_add_device(struct bttv_core *core, char *name)
7268de959fSMauro Carvalho Chehab {
7368de959fSMauro Carvalho Chehab 	struct bttv_sub_device *sub;
7468de959fSMauro Carvalho Chehab 	int err;
7568de959fSMauro Carvalho Chehab 
7668de959fSMauro Carvalho Chehab 	sub = kzalloc(sizeof(*sub),GFP_KERNEL);
7768de959fSMauro Carvalho Chehab 	if (NULL == sub)
7868de959fSMauro Carvalho Chehab 		return -ENOMEM;
7968de959fSMauro Carvalho Chehab 
8068de959fSMauro Carvalho Chehab 	sub->core        = core;
8168de959fSMauro Carvalho Chehab 	sub->dev.parent  = &core->pci->dev;
8268de959fSMauro Carvalho Chehab 	sub->dev.bus     = &bttv_sub_bus_type;
8368de959fSMauro Carvalho Chehab 	sub->dev.release = release_sub_device;
8468de959fSMauro Carvalho Chehab 	dev_set_name(&sub->dev, "%s%d", name, core->nr);
8568de959fSMauro Carvalho Chehab 
8668de959fSMauro Carvalho Chehab 	err = device_register(&sub->dev);
8768de959fSMauro Carvalho Chehab 	if (0 != err) {
8838121b6eSLevente Kurusa 		put_device(&sub->dev);
8968de959fSMauro Carvalho Chehab 		return err;
9068de959fSMauro Carvalho Chehab 	}
9168de959fSMauro Carvalho Chehab 	pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
9268de959fSMauro Carvalho Chehab 	list_add_tail(&sub->list,&core->subs);
9368de959fSMauro Carvalho Chehab 	return 0;
9468de959fSMauro Carvalho Chehab }
9568de959fSMauro Carvalho Chehab 
bttv_sub_del_devices(struct bttv_core * core)9668de959fSMauro Carvalho Chehab int bttv_sub_del_devices(struct bttv_core *core)
9768de959fSMauro Carvalho Chehab {
9868de959fSMauro Carvalho Chehab 	struct bttv_sub_device *sub, *save;
9968de959fSMauro Carvalho Chehab 
10068de959fSMauro Carvalho Chehab 	list_for_each_entry_safe(sub, save, &core->subs, list) {
10168de959fSMauro Carvalho Chehab 		list_del(&sub->list);
10268de959fSMauro Carvalho Chehab 		device_unregister(&sub->dev);
10368de959fSMauro Carvalho Chehab 	}
10468de959fSMauro Carvalho Chehab 	return 0;
10568de959fSMauro Carvalho Chehab }
10668de959fSMauro Carvalho Chehab 
10768de959fSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
10868de959fSMauro Carvalho Chehab /* external: sub-driver register/unregister                                */
10968de959fSMauro Carvalho Chehab 
bttv_sub_register(struct bttv_sub_driver * sub,char * wanted)11068de959fSMauro Carvalho Chehab int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted)
11168de959fSMauro Carvalho Chehab {
11268de959fSMauro Carvalho Chehab 	sub->drv.bus = &bttv_sub_bus_type;
11368de959fSMauro Carvalho Chehab 	snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted);
11468de959fSMauro Carvalho Chehab 	return driver_register(&sub->drv);
11568de959fSMauro Carvalho Chehab }
11668de959fSMauro Carvalho Chehab EXPORT_SYMBOL(bttv_sub_register);
11768de959fSMauro Carvalho Chehab 
bttv_sub_unregister(struct bttv_sub_driver * sub)11868de959fSMauro Carvalho Chehab int bttv_sub_unregister(struct bttv_sub_driver *sub)
11968de959fSMauro Carvalho Chehab {
12068de959fSMauro Carvalho Chehab 	driver_unregister(&sub->drv);
12168de959fSMauro Carvalho Chehab 	return 0;
12268de959fSMauro Carvalho Chehab }
12368de959fSMauro Carvalho Chehab EXPORT_SYMBOL(bttv_sub_unregister);
12468de959fSMauro Carvalho Chehab 
12568de959fSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
12668de959fSMauro Carvalho Chehab /* external: gpio access functions                                         */
12768de959fSMauro Carvalho Chehab 
bttv_gpio_inout(struct bttv_core * core,u32 mask,u32 outbits)12868de959fSMauro Carvalho Chehab void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits)
12968de959fSMauro Carvalho Chehab {
13068de959fSMauro Carvalho Chehab 	struct bttv *btv = container_of(core, struct bttv, c);
13168de959fSMauro Carvalho Chehab 	unsigned long flags;
13268de959fSMauro Carvalho Chehab 	u32 data;
13368de959fSMauro Carvalho Chehab 
13468de959fSMauro Carvalho Chehab 	spin_lock_irqsave(&btv->gpio_lock,flags);
13568de959fSMauro Carvalho Chehab 	data = btread(BT848_GPIO_OUT_EN);
13668de959fSMauro Carvalho Chehab 	data = data & ~mask;
13768de959fSMauro Carvalho Chehab 	data = data | (mask & outbits);
13868de959fSMauro Carvalho Chehab 	btwrite(data,BT848_GPIO_OUT_EN);
13968de959fSMauro Carvalho Chehab 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
14068de959fSMauro Carvalho Chehab }
14168de959fSMauro Carvalho Chehab 
bttv_gpio_read(struct bttv_core * core)14268de959fSMauro Carvalho Chehab u32 bttv_gpio_read(struct bttv_core *core)
14368de959fSMauro Carvalho Chehab {
14468de959fSMauro Carvalho Chehab 	struct bttv *btv = container_of(core, struct bttv, c);
14568de959fSMauro Carvalho Chehab 	u32 value;
14668de959fSMauro Carvalho Chehab 
14768de959fSMauro Carvalho Chehab 	value = btread(BT848_GPIO_DATA);
14868de959fSMauro Carvalho Chehab 	return value;
14968de959fSMauro Carvalho Chehab }
15068de959fSMauro Carvalho Chehab 
bttv_gpio_write(struct bttv_core * core,u32 value)15168de959fSMauro Carvalho Chehab void bttv_gpio_write(struct bttv_core *core, u32 value)
15268de959fSMauro Carvalho Chehab {
15368de959fSMauro Carvalho Chehab 	struct bttv *btv = container_of(core, struct bttv, c);
15468de959fSMauro Carvalho Chehab 
15568de959fSMauro Carvalho Chehab 	btwrite(value,BT848_GPIO_DATA);
15668de959fSMauro Carvalho Chehab }
15768de959fSMauro Carvalho Chehab 
bttv_gpio_bits(struct bttv_core * core,u32 mask,u32 bits)15868de959fSMauro Carvalho Chehab void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
15968de959fSMauro Carvalho Chehab {
16068de959fSMauro Carvalho Chehab 	struct bttv *btv = container_of(core, struct bttv, c);
16168de959fSMauro Carvalho Chehab 	unsigned long flags;
16268de959fSMauro Carvalho Chehab 	u32 data;
16368de959fSMauro Carvalho Chehab 
16468de959fSMauro Carvalho Chehab 	spin_lock_irqsave(&btv->gpio_lock,flags);
16568de959fSMauro Carvalho Chehab 	data = btread(BT848_GPIO_DATA);
16668de959fSMauro Carvalho Chehab 	data = data & ~mask;
16768de959fSMauro Carvalho Chehab 	data = data | (mask & bits);
16868de959fSMauro Carvalho Chehab 	btwrite(data,BT848_GPIO_DATA);
16968de959fSMauro Carvalho Chehab 	spin_unlock_irqrestore(&btv->gpio_lock,flags);
17068de959fSMauro Carvalho Chehab }
171