Skip to content

Commit d3202d1

Browse files
antonsviridenkomchehab
authored andcommitted
media: solo6x10: export hardware GPIO pins 8:31 to gpiolib interface
24 GPIO pins from 32 available on solo6x10 chips are exported to gpiolib. First 8 GPIOs are reserved for internal use on capture card boards, GPIOs in range 8:15 are configured as outputs to control relays, remaining 16:31 are configured as inputs to read sensor states. Now with this patch userspace DVR software can switch relays and read sensor states when GPIO extension cards are attached to Softlogic solo6x10 based video capture cards. Signed-off-by: Anton Sviridenko <[email protected]> Signed-off-by: Ismael Luceno <[email protected]> Signed-off-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 2246902 commit d3202d1

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

drivers/media/pci/solo6x10/solo6x10-gpio.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ static void solo_gpio_mode(struct solo_dev *solo_dev,
5757
ret |= 1 << port;
5858
}
5959

60+
/* Enable GPIO[31:16] */
61+
ret |= 0xffff0000;
62+
6063
solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
6164
}
6265

@@ -90,16 +93,110 @@ static void solo_gpio_config(struct solo_dev *solo_dev)
9093

9194
/* Initially set relay status to 0 */
9295
solo_gpio_clear(solo_dev, 0xff00);
96+
97+
/* Set input pins direction */
98+
solo_gpio_mode(solo_dev, 0xffff0000, 0);
99+
}
100+
101+
#ifdef CONFIG_GPIOLIB
102+
/* Pins 0-7 are not exported, because it seems from code above they are
103+
* used for internal purposes. So offset 0 corresponds to pin 8, therefore
104+
* offsets 0-7 are relay GPIOs, 8-23 - input GPIOs.
105+
*/
106+
static int solo_gpiochip_get_direction(struct gpio_chip *chip,
107+
unsigned int offset)
108+
{
109+
int ret, mode;
110+
struct solo_dev *solo_dev = gpiochip_get_data(chip);
111+
112+
if (offset < 8) {
113+
ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
114+
mode = 3 & (ret >> ((offset + 8) * 2));
115+
} else {
116+
ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
117+
mode = 1 & (ret >> (offset - 8));
118+
}
119+
120+
if (!mode)
121+
return 1;
122+
else if (mode == 1)
123+
return 0;
124+
125+
return -1;
93126
}
94127

128+
static int solo_gpiochip_direction_input(struct gpio_chip *chip,
129+
unsigned int offset)
130+
{
131+
return -1;
132+
}
133+
134+
static int solo_gpiochip_direction_output(struct gpio_chip *chip,
135+
unsigned int offset, int value)
136+
{
137+
return -1;
138+
}
139+
140+
static int solo_gpiochip_get(struct gpio_chip *chip,
141+
unsigned int offset)
142+
{
143+
int ret;
144+
struct solo_dev *solo_dev = gpiochip_get_data(chip);
145+
146+
ret = solo_reg_read(solo_dev, SOLO_GPIO_DATA_IN);
147+
148+
return 1 & (ret >> (offset + 8));
149+
}
150+
151+
static void solo_gpiochip_set(struct gpio_chip *chip,
152+
unsigned int offset, int value)
153+
{
154+
struct solo_dev *solo_dev = gpiochip_get_data(chip);
155+
156+
if (value)
157+
solo_gpio_set(solo_dev, 1 << (offset + 8));
158+
else
159+
solo_gpio_clear(solo_dev, 1 << (offset + 8));
160+
}
161+
#endif
162+
95163
int solo_gpio_init(struct solo_dev *solo_dev)
96164
{
165+
int ret;
166+
97167
solo_gpio_config(solo_dev);
168+
#ifdef CONFIG_GPIOLIB
169+
solo_dev->gpio_dev.label = SOLO6X10_NAME"_gpio";
170+
solo_dev->gpio_dev.parent = &solo_dev->pdev->dev;
171+
solo_dev->gpio_dev.owner = THIS_MODULE;
172+
solo_dev->gpio_dev.base = -1;
173+
solo_dev->gpio_dev.ngpio = 24;
174+
solo_dev->gpio_dev.can_sleep = 0;
175+
176+
solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction;
177+
solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input;
178+
solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output;
179+
solo_dev->gpio_dev.get = solo_gpiochip_get;
180+
solo_dev->gpio_dev.set = solo_gpiochip_set;
181+
182+
ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev);
183+
184+
if (ret) {
185+
solo_dev->gpio_dev.label = NULL;
186+
return -1;
187+
}
188+
#endif
98189
return 0;
99190
}
100191

101192
void solo_gpio_exit(struct solo_dev *solo_dev)
102193
{
194+
#ifdef CONFIG_GPIOLIB
195+
if (solo_dev->gpio_dev.label) {
196+
gpiochip_remove(&solo_dev->gpio_dev);
197+
solo_dev->gpio_dev.label = NULL;
198+
}
199+
#endif
103200
solo_gpio_clear(solo_dev, 0x30);
104201
solo_gpio_config(solo_dev);
105202
}

drivers/media/pci/solo6x10/solo6x10.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/atomic.h>
3232
#include <linux/slab.h>
3333
#include <linux/videodev2.h>
34+
#include <linux/gpio/driver.h>
3435

3536
#include <media/v4l2-dev.h>
3637
#include <media/v4l2-device.h>
@@ -199,6 +200,10 @@ struct solo_dev {
199200
u32 irq_mask;
200201
u32 motion_mask;
201202
struct v4l2_device v4l2_dev;
203+
#ifdef CONFIG_GPIOLIB
204+
/* GPIO */
205+
struct gpio_chip gpio_dev;
206+
#endif
202207

203208
/* tw28xx accounting */
204209
u8 tw2865, tw2864, tw2815;

0 commit comments

Comments
 (0)