162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci bttv-gpio.c -- gpio sub drivers 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci sysfs-based sub driver interface for bttv 762306a36Sopenharmony_ci mainly intended for gpio access 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) 1162306a36Sopenharmony_ci & Marcus Metzler (mocm@thp.uni-koeln.de) 1262306a36Sopenharmony_ci (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci*/ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/device.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <asm/io.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "bttvp.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */ 2962306a36Sopenharmony_ci/* internal: the bttv "bus" */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); 3462306a36Sopenharmony_ci int len = strlen(sub->wanted); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (0 == strncmp(dev_name(dev), sub->wanted, len)) 3762306a36Sopenharmony_ci return 1; 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int bttv_sub_probe(struct device *dev) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); 4462306a36Sopenharmony_ci struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return sub->probe ? sub->probe(sdev) : -ENODEV; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void bttv_sub_remove(struct device *dev) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); 5262306a36Sopenharmony_ci struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (sub->remove) 5562306a36Sopenharmony_ci sub->remove(sdev); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct bus_type bttv_sub_bus_type = { 5962306a36Sopenharmony_ci .name = "bttv-sub", 6062306a36Sopenharmony_ci .match = &bttv_sub_bus_match, 6162306a36Sopenharmony_ci .probe = bttv_sub_probe, 6262306a36Sopenharmony_ci .remove = bttv_sub_remove, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void release_sub_device(struct device *dev) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct bttv_sub_device *sub = to_bttv_sub_dev(dev); 6862306a36Sopenharmony_ci kfree(sub); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciint bttv_sub_add_device(struct bttv_core *core, char *name) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct bttv_sub_device *sub; 7462306a36Sopenharmony_ci int err; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci sub = kzalloc(sizeof(*sub),GFP_KERNEL); 7762306a36Sopenharmony_ci if (NULL == sub) 7862306a36Sopenharmony_ci return -ENOMEM; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci sub->core = core; 8162306a36Sopenharmony_ci sub->dev.parent = &core->pci->dev; 8262306a36Sopenharmony_ci sub->dev.bus = &bttv_sub_bus_type; 8362306a36Sopenharmony_ci sub->dev.release = release_sub_device; 8462306a36Sopenharmony_ci dev_set_name(&sub->dev, "%s%d", name, core->nr); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci err = device_register(&sub->dev); 8762306a36Sopenharmony_ci if (0 != err) { 8862306a36Sopenharmony_ci put_device(&sub->dev); 8962306a36Sopenharmony_ci return err; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); 9262306a36Sopenharmony_ci list_add_tail(&sub->list,&core->subs); 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciint bttv_sub_del_devices(struct bttv_core *core) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct bttv_sub_device *sub, *save; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci list_for_each_entry_safe(sub, save, &core->subs, list) { 10162306a36Sopenharmony_ci list_del(&sub->list); 10262306a36Sopenharmony_ci device_unregister(&sub->dev); 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */ 10862306a36Sopenharmony_ci/* external: sub-driver register/unregister */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciint bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci sub->drv.bus = &bttv_sub_bus_type; 11362306a36Sopenharmony_ci snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); 11462306a36Sopenharmony_ci return driver_register(&sub->drv); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ciEXPORT_SYMBOL(bttv_sub_register); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciint bttv_sub_unregister(struct bttv_sub_driver *sub) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci driver_unregister(&sub->drv); 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ciEXPORT_SYMBOL(bttv_sub_unregister); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */ 12662306a36Sopenharmony_ci/* external: gpio access functions */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_civoid bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct bttv *btv = container_of(core, struct bttv, c); 13162306a36Sopenharmony_ci unsigned long flags; 13262306a36Sopenharmony_ci u32 data; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci spin_lock_irqsave(&btv->gpio_lock,flags); 13562306a36Sopenharmony_ci data = btread(BT848_GPIO_OUT_EN); 13662306a36Sopenharmony_ci data = data & ~mask; 13762306a36Sopenharmony_ci data = data | (mask & outbits); 13862306a36Sopenharmony_ci btwrite(data,BT848_GPIO_OUT_EN); 13962306a36Sopenharmony_ci spin_unlock_irqrestore(&btv->gpio_lock,flags); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ciu32 bttv_gpio_read(struct bttv_core *core) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct bttv *btv = container_of(core, struct bttv, c); 14562306a36Sopenharmony_ci u32 value; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci value = btread(BT848_GPIO_DATA); 14862306a36Sopenharmony_ci return value; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_civoid bttv_gpio_write(struct bttv_core *core, u32 value) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct bttv *btv = container_of(core, struct bttv, c); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci btwrite(value,BT848_GPIO_DATA); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_civoid bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct bttv *btv = container_of(core, struct bttv, c); 16162306a36Sopenharmony_ci unsigned long flags; 16262306a36Sopenharmony_ci u32 data; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci spin_lock_irqsave(&btv->gpio_lock,flags); 16562306a36Sopenharmony_ci data = btread(BT848_GPIO_DATA); 16662306a36Sopenharmony_ci data = data & ~mask; 16762306a36Sopenharmony_ci data = data | (mask & bits); 16862306a36Sopenharmony_ci btwrite(data,BT848_GPIO_DATA); 16962306a36Sopenharmony_ci spin_unlock_irqrestore(&btv->gpio_lock,flags); 17062306a36Sopenharmony_ci} 171