1
2
3
4
5
6
7
8
9
10#include <linux/module.h>
11#include <linux/types.h>
12#include <linux/slab.h>
13#include <linux/ioctl.h>
14#include <linux/uaccess.h>
15#include <linux/i2c.h>
16#include <linux/videodev2.h>
17#include <media/i2c/m52790.h>
18#include <media/v4l2-device.h>
19
20MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
21MODULE_AUTHOR("Hans Verkuil");
22MODULE_LICENSE("GPL");
23
24
25struct m52790_state {
26 struct v4l2_subdev sd;
27 u16 input;
28 u16 output;
29};
30
31static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
32{
33 return container_of(sd, struct m52790_state, sd);
34}
35
36
37
38static int m52790_write(struct v4l2_subdev *sd)
39{
40 struct m52790_state *state = to_state(sd);
41 struct i2c_client *client = v4l2_get_subdevdata(sd);
42
43 u8 sw1 = (state->input | state->output) & 0xff;
44 u8 sw2 = (state->input | state->output) >> 8;
45
46 return i2c_smbus_write_byte_data(client, sw1, sw2);
47}
48
49
50
51
52
53
54
55
56
57static int m52790_s_routing(struct v4l2_subdev *sd,
58 u32 input, u32 output, u32 config)
59{
60 struct m52790_state *state = to_state(sd);
61
62 state->input = input;
63 state->output = output;
64 m52790_write(sd);
65 return 0;
66}
67
68#ifdef CONFIG_VIDEO_ADV_DEBUG
69static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
70{
71 struct m52790_state *state = to_state(sd);
72
73 if (reg->reg != 0)
74 return -EINVAL;
75 reg->size = 1;
76 reg->val = state->input | state->output;
77 return 0;
78}
79
80static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
81{
82 struct m52790_state *state = to_state(sd);
83
84 if (reg->reg != 0)
85 return -EINVAL;
86 state->input = reg->val & 0x0303;
87 state->output = reg->val & ~0x0303;
88 m52790_write(sd);
89 return 0;
90}
91#endif
92
93static int m52790_log_status(struct v4l2_subdev *sd)
94{
95 struct m52790_state *state = to_state(sd);
96
97 v4l2_info(sd, "Switch 1: %02x\n",
98 (state->input | state->output) & 0xff);
99 v4l2_info(sd, "Switch 2: %02x\n",
100 (state->input | state->output) >> 8);
101 return 0;
102}
103
104
105
106static const struct v4l2_subdev_core_ops m52790_core_ops = {
107 .log_status = m52790_log_status,
108#ifdef CONFIG_VIDEO_ADV_DEBUG
109 .g_register = m52790_g_register,
110 .s_register = m52790_s_register,
111#endif
112};
113
114static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
115 .s_routing = m52790_s_routing,
116};
117
118static const struct v4l2_subdev_video_ops m52790_video_ops = {
119 .s_routing = m52790_s_routing,
120};
121
122static const struct v4l2_subdev_ops m52790_ops = {
123 .core = &m52790_core_ops,
124 .audio = &m52790_audio_ops,
125 .video = &m52790_video_ops,
126};
127
128
129
130
131
132static int m52790_probe(struct i2c_client *client,
133 const struct i2c_device_id *id)
134{
135 struct m52790_state *state;
136 struct v4l2_subdev *sd;
137
138
139 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
140 return -EIO;
141
142 v4l_info(client, "chip found @ 0x%x (%s)\n",
143 client->addr << 1, client->adapter->name);
144
145 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
146 if (state == NULL)
147 return -ENOMEM;
148
149 sd = &state->sd;
150 v4l2_i2c_subdev_init(sd, client, &m52790_ops);
151 state->input = M52790_IN_TUNER;
152 state->output = M52790_OUT_STEREO;
153 m52790_write(sd);
154 return 0;
155}
156
157static int m52790_remove(struct i2c_client *client)
158{
159 struct v4l2_subdev *sd = i2c_get_clientdata(client);
160
161 v4l2_device_unregister_subdev(sd);
162 return 0;
163}
164
165
166
167static const struct i2c_device_id m52790_id[] = {
168 { "m52790", 0 },
169 { }
170};
171MODULE_DEVICE_TABLE(i2c, m52790_id);
172
173static struct i2c_driver m52790_driver = {
174 .driver = {
175 .name = "m52790",
176 },
177 .probe = m52790_probe,
178 .remove = m52790_remove,
179 .id_table = m52790_id,
180};
181
182module_i2c_driver(m52790_driver);
183