Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / media / tuners / tuner-i2c.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3     tuner-i2c.h - i2c interface for different tuners
4
5     Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
6
7 */
8
9 #ifndef __TUNER_I2C_H__
10 #define __TUNER_I2C_H__
11
12 #include <linux/i2c.h>
13 #include <linux/slab.h>
14
15 struct tuner_i2c_props {
16         u8 addr;
17         struct i2c_adapter *adap;
18
19         /* used for tuner instance management */
20         int count;
21         char *name;
22 };
23
24 static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props,
25                                       unsigned char *buf, int len)
26 {
27         struct i2c_msg msg = { .addr = props->addr, .flags = 0,
28                                .buf = buf, .len = len };
29         int ret = i2c_transfer(props->adap, &msg, 1);
30
31         return (ret == 1) ? len : ret;
32 }
33
34 static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props,
35                                       unsigned char *buf, int len)
36 {
37         struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
38                                .buf = buf, .len = len };
39         int ret = i2c_transfer(props->adap, &msg, 1);
40
41         return (ret == 1) ? len : ret;
42 }
43
44 static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
45                                            unsigned char *obuf, int olen,
46                                            unsigned char *ibuf, int ilen)
47 {
48         struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
49                                     .buf = obuf, .len = olen },
50                                   { .addr = props->addr, .flags = I2C_M_RD,
51                                     .buf = ibuf, .len = ilen } };
52         int ret = i2c_transfer(props->adap, msg, 2);
53
54         return (ret == 2) ? ilen : ret;
55 }
56
57 /* Callers must declare as a global for the module:
58  *
59  * static LIST_HEAD(hybrid_tuner_instance_list);
60  *
61  * hybrid_tuner_instance_list should be the third argument
62  * passed into hybrid_tuner_request_state().
63  *
64  * state structure must contain the following:
65  *
66  *      struct list_head        hybrid_tuner_instance_list;
67  *      struct tuner_i2c_props  i2c_props;
68  *
69  * hybrid_tuner_instance_list (both within state structure and globally)
70  * is only required if the driver is using hybrid_tuner_request_state
71  * and hybrid_tuner_release_state to manage state sharing between
72  * multiple instances of hybrid tuners.
73  */
74
75 #define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {               \
76         printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,               \
77                         i2cprops.adap ?                                 \
78                                 i2c_adapter_id(i2cprops.adap) : -1,     \
79                         i2cprops.addr, ##arg);                          \
80          } while (0)
81
82 /* TO DO: convert all callers of these macros to pass in
83  * struct tuner_i2c_props, then remove the macro wrappers */
84
85 #define __tuner_warn(i2cprops, fmt, arg...) do {                        \
86         tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);               \
87         } while (0)
88
89 #define __tuner_info(i2cprops, fmt, arg...) do {                        \
90         tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);                  \
91         } while (0)
92
93 #define __tuner_err(i2cprops, fmt, arg...) do {                         \
94         tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);                   \
95         } while (0)
96
97 #define __tuner_dbg(i2cprops, fmt, arg...) do {                         \
98         if ((debug))                                                    \
99                 tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);         \
100         } while (0)
101
102 #define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
103 #define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
104 #define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
105 #define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
106
107 /****************************************************************************/
108
109 /* The return value of hybrid_tuner_request_state indicates the number of
110  * instances using this tuner object.
111  *
112  * 0 - no instances, indicates an error - kzalloc must have failed
113  *
114  * 1 - one instance, indicates that the tuner object was created successfully
115  *
116  * 2 (or more) instances, indicates that an existing tuner object was found
117  */
118
119 #define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
120 ({                                                                      \
121         int __ret = 0;                                                  \
122         list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \
123                 if (((i2cadap) && (state->i2c_props.adap)) &&           \
124                     ((i2c_adapter_id(state->i2c_props.adap) ==          \
125                       i2c_adapter_id(i2cadap)) &&                       \
126                      (i2caddr == state->i2c_props.addr))) {             \
127                         __tuner_info(state->i2c_props,                  \
128                                      "attaching existing instance\n");  \
129                         state->i2c_props.count++;                       \
130                         __ret = state->i2c_props.count;                 \
131                         break;                                          \
132                 }                                                       \
133         }                                                               \
134         if (0 == __ret) {                                               \
135                 state = kzalloc(sizeof(type), GFP_KERNEL);              \
136                 if (NULL == state)                                      \
137                         goto __fail;                                    \
138                 state->i2c_props.addr = i2caddr;                        \
139                 state->i2c_props.adap = i2cadap;                        \
140                 state->i2c_props.name = devname;                        \
141                 __tuner_info(state->i2c_props,                          \
142                              "creating new instance\n");                \
143                 list_add_tail(&state->hybrid_tuner_instance_list, &list);\
144                 state->i2c_props.count++;                               \
145                 __ret = state->i2c_props.count;                         \
146         }                                                               \
147 __fail:                                                                 \
148         __ret;                                                          \
149 })
150
151 #define hybrid_tuner_release_state(state)                               \
152 ({                                                                      \
153         int __ret;                                                      \
154         state->i2c_props.count--;                                       \
155         __ret = state->i2c_props.count;                                 \
156         if (!state->i2c_props.count) {                                  \
157                 __tuner_info(state->i2c_props, "destroying instance\n");\
158                 list_del(&state->hybrid_tuner_instance_list);           \
159                 kfree(state);                                           \
160         }                                                               \
161         __ret;                                                          \
162 })
163
164 #define hybrid_tuner_report_instance_count(state)                       \
165 ({                                                                      \
166         int __ret = 0;                                                  \
167         if (state)                                                      \
168                 __ret = state->i2c_props.count;                         \
169         __ret;                                                          \
170 })
171
172 #endif /* __TUNER_I2C_H__ */