1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | |
4 | bttv-gpio.c -- gpio sub drivers |
5 | |
6 | sysfs-based sub driver interface for bttv |
7 | mainly intended for gpio access |
8 | |
9 | |
10 | Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) |
11 | & Marcus Metzler (mocm@thp.uni-koeln.de) |
12 | (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org> |
13 | |
14 | |
15 | */ |
16 | |
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
18 | |
19 | #include <linux/module.h> |
20 | #include <linux/init.h> |
21 | #include <linux/delay.h> |
22 | #include <linux/device.h> |
23 | #include <linux/slab.h> |
24 | #include <asm/io.h> |
25 | |
26 | #include "bttvp.h" |
27 | |
28 | /* ----------------------------------------------------------------------- */ |
29 | /* internal: the bttv "bus" */ |
30 | |
31 | static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) |
32 | { |
33 | struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); |
34 | int len = strlen(sub->wanted); |
35 | |
36 | if (0 == strncmp(dev_name(dev), sub->wanted, len)) |
37 | return 1; |
38 | return 0; |
39 | } |
40 | |
41 | static int bttv_sub_probe(struct device *dev) |
42 | { |
43 | struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); |
44 | struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); |
45 | |
46 | return sub->probe ? sub->probe(sdev) : -ENODEV; |
47 | } |
48 | |
49 | static void bttv_sub_remove(struct device *dev) |
50 | { |
51 | struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); |
52 | struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); |
53 | |
54 | if (sub->remove) |
55 | sub->remove(sdev); |
56 | } |
57 | |
58 | const struct bus_type bttv_sub_bus_type = { |
59 | .name = "bttv-sub" , |
60 | .match = &bttv_sub_bus_match, |
61 | .probe = bttv_sub_probe, |
62 | .remove = bttv_sub_remove, |
63 | }; |
64 | |
65 | static void release_sub_device(struct device *dev) |
66 | { |
67 | struct bttv_sub_device *sub = to_bttv_sub_dev(dev); |
68 | kfree(objp: sub); |
69 | } |
70 | |
71 | int bttv_sub_add_device(struct bttv_core *core, char *name) |
72 | { |
73 | struct bttv_sub_device *sub; |
74 | int err; |
75 | |
76 | sub = kzalloc(size: sizeof(*sub),GFP_KERNEL); |
77 | if (NULL == sub) |
78 | return -ENOMEM; |
79 | |
80 | sub->core = core; |
81 | sub->dev.parent = &core->pci->dev; |
82 | sub->dev.bus = &bttv_sub_bus_type; |
83 | sub->dev.release = release_sub_device; |
84 | dev_set_name(dev: &sub->dev, name: "%s%d" , name, core->nr); |
85 | |
86 | err = device_register(dev: &sub->dev); |
87 | if (0 != err) { |
88 | put_device(dev: &sub->dev); |
89 | return err; |
90 | } |
91 | pr_info("%d: add subdevice \"%s\"\n" , core->nr, dev_name(&sub->dev)); |
92 | list_add_tail(new: &sub->list,head: &core->subs); |
93 | return 0; |
94 | } |
95 | |
96 | int bttv_sub_del_devices(struct bttv_core *core) |
97 | { |
98 | struct bttv_sub_device *sub, *save; |
99 | |
100 | list_for_each_entry_safe(sub, save, &core->subs, list) { |
101 | list_del(entry: &sub->list); |
102 | device_unregister(dev: &sub->dev); |
103 | } |
104 | return 0; |
105 | } |
106 | |
107 | /* ----------------------------------------------------------------------- */ |
108 | /* external: sub-driver register/unregister */ |
109 | |
110 | int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) |
111 | { |
112 | sub->drv.bus = &bttv_sub_bus_type; |
113 | snprintf(buf: sub->wanted,size: sizeof(sub->wanted),fmt: "%s" ,wanted); |
114 | return driver_register(drv: &sub->drv); |
115 | } |
116 | EXPORT_SYMBOL(bttv_sub_register); |
117 | |
118 | int bttv_sub_unregister(struct bttv_sub_driver *sub) |
119 | { |
120 | driver_unregister(drv: &sub->drv); |
121 | return 0; |
122 | } |
123 | EXPORT_SYMBOL(bttv_sub_unregister); |
124 | |
125 | /* ----------------------------------------------------------------------- */ |
126 | /* external: gpio access functions */ |
127 | |
128 | void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) |
129 | { |
130 | struct bttv *btv = container_of(core, struct bttv, c); |
131 | unsigned long flags; |
132 | u32 data; |
133 | |
134 | spin_lock_irqsave(&btv->gpio_lock,flags); |
135 | data = btread(BT848_GPIO_OUT_EN); |
136 | data = data & ~mask; |
137 | data = data | (mask & outbits); |
138 | btwrite(data,BT848_GPIO_OUT_EN); |
139 | spin_unlock_irqrestore(lock: &btv->gpio_lock,flags); |
140 | } |
141 | |
142 | u32 bttv_gpio_read(struct bttv_core *core) |
143 | { |
144 | struct bttv *btv = container_of(core, struct bttv, c); |
145 | u32 value; |
146 | |
147 | value = btread(BT848_GPIO_DATA); |
148 | return value; |
149 | } |
150 | |
151 | void bttv_gpio_write(struct bttv_core *core, u32 value) |
152 | { |
153 | struct bttv *btv = container_of(core, struct bttv, c); |
154 | |
155 | btwrite(value,BT848_GPIO_DATA); |
156 | } |
157 | |
158 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) |
159 | { |
160 | struct bttv *btv = container_of(core, struct bttv, c); |
161 | unsigned long flags; |
162 | u32 data; |
163 | |
164 | spin_lock_irqsave(&btv->gpio_lock,flags); |
165 | data = btread(BT848_GPIO_DATA); |
166 | data = data & ~mask; |
167 | data = data | (mask & bits); |
168 | btwrite(data,BT848_GPIO_DATA); |
169 | spin_unlock_irqrestore(lock: &btv->gpio_lock,flags); |
170 | } |
171 | |