Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003     tuner-i2c.h - i2c interface for different tuners
0004 
0005     Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
0006 
0007 */
0008 
0009 #ifndef __TUNER_I2C_H__
0010 #define __TUNER_I2C_H__
0011 
0012 #include <linux/i2c.h>
0013 #include <linux/slab.h>
0014 
0015 struct tuner_i2c_props {
0016     u8 addr;
0017     struct i2c_adapter *adap;
0018 
0019     /* used for tuner instance management */
0020     int count;
0021     char *name;
0022 };
0023 
0024 static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props,
0025                       unsigned char *buf, int len)
0026 {
0027     struct i2c_msg msg = { .addr = props->addr, .flags = 0,
0028                    .buf = buf, .len = len };
0029     int ret = i2c_transfer(props->adap, &msg, 1);
0030 
0031     return (ret == 1) ? len : ret;
0032 }
0033 
0034 static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props,
0035                       unsigned char *buf, int len)
0036 {
0037     struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
0038                    .buf = buf, .len = len };
0039     int ret = i2c_transfer(props->adap, &msg, 1);
0040 
0041     return (ret == 1) ? len : ret;
0042 }
0043 
0044 static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
0045                        unsigned char *obuf, int olen,
0046                        unsigned char *ibuf, int ilen)
0047 {
0048     struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
0049                     .buf = obuf, .len = olen },
0050                   { .addr = props->addr, .flags = I2C_M_RD,
0051                     .buf = ibuf, .len = ilen } };
0052     int ret = i2c_transfer(props->adap, msg, 2);
0053 
0054     return (ret == 2) ? ilen : ret;
0055 }
0056 
0057 /* Callers must declare as a global for the module:
0058  *
0059  * static LIST_HEAD(hybrid_tuner_instance_list);
0060  *
0061  * hybrid_tuner_instance_list should be the third argument
0062  * passed into hybrid_tuner_request_state().
0063  *
0064  * state structure must contain the following:
0065  *
0066  *  struct list_head    hybrid_tuner_instance_list;
0067  *  struct tuner_i2c_props  i2c_props;
0068  *
0069  * hybrid_tuner_instance_list (both within state structure and globally)
0070  * is only required if the driver is using hybrid_tuner_request_state
0071  * and hybrid_tuner_release_state to manage state sharing between
0072  * multiple instances of hybrid tuners.
0073  */
0074 
0075 #define tuner_printk(kernlvl, i2cprops, fmt, arg...) do {       \
0076     printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name,       \
0077             i2cprops.adap ?                 \
0078                 i2c_adapter_id(i2cprops.adap) : -1, \
0079             i2cprops.addr, ##arg);              \
0080      } while (0)
0081 
0082 /* TO DO: convert all callers of these macros to pass in
0083  * struct tuner_i2c_props, then remove the macro wrappers */
0084 
0085 #define __tuner_warn(i2cprops, fmt, arg...) do {            \
0086     tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg);       \
0087     } while (0)
0088 
0089 #define __tuner_info(i2cprops, fmt, arg...) do {            \
0090     tuner_printk(KERN_INFO, i2cprops, fmt, ##arg);          \
0091     } while (0)
0092 
0093 #define __tuner_err(i2cprops, fmt, arg...) do {             \
0094     tuner_printk(KERN_ERR, i2cprops, fmt, ##arg);           \
0095     } while (0)
0096 
0097 #define __tuner_dbg(i2cprops, fmt, arg...) do {             \
0098     if ((debug))                            \
0099         tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg);     \
0100     } while (0)
0101 
0102 #define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
0103 #define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
0104 #define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
0105 #define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
0106 
0107 /****************************************************************************/
0108 
0109 /* The return value of hybrid_tuner_request_state indicates the number of
0110  * instances using this tuner object.
0111  *
0112  * 0 - no instances, indicates an error - kzalloc must have failed
0113  *
0114  * 1 - one instance, indicates that the tuner object was created successfully
0115  *
0116  * 2 (or more) instances, indicates that an existing tuner object was found
0117  */
0118 
0119 #define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
0120 ({                                  \
0121     int __ret = 0;                          \
0122     list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \
0123         if (((i2cadap) && (state->i2c_props.adap)) &&       \
0124             ((i2c_adapter_id(state->i2c_props.adap) ==      \
0125               i2c_adapter_id(i2cadap)) &&           \
0126              (i2caddr == state->i2c_props.addr))) {     \
0127             __tuner_info(state->i2c_props,          \
0128                      "attaching existing instance\n");  \
0129             state->i2c_props.count++;           \
0130             __ret = state->i2c_props.count;         \
0131             break;                      \
0132         }                           \
0133     }                               \
0134     if (0 == __ret) {                       \
0135         state = kzalloc(sizeof(type), GFP_KERNEL);      \
0136         if (!state) {                       \
0137             __ret = -ENOMEM;                \
0138             goto __fail;                    \
0139         }                           \
0140         state->i2c_props.addr = i2caddr;            \
0141         state->i2c_props.adap = i2cadap;            \
0142         state->i2c_props.name = devname;            \
0143         __tuner_info(state->i2c_props,              \
0144                  "creating new instance\n");        \
0145         list_add_tail(&state->hybrid_tuner_instance_list, &list);\
0146         state->i2c_props.count++;               \
0147         __ret = state->i2c_props.count;             \
0148     }                               \
0149 __fail:                                 \
0150     __ret;                              \
0151 })
0152 
0153 #define hybrid_tuner_release_state(state)               \
0154 ({                                  \
0155     int __ret;                          \
0156     state->i2c_props.count--;                   \
0157     __ret = state->i2c_props.count;                 \
0158     if (!state->i2c_props.count) {                  \
0159         __tuner_info(state->i2c_props, "destroying instance\n");\
0160         list_del(&state->hybrid_tuner_instance_list);       \
0161         kfree(state);                       \
0162     }                               \
0163     __ret;                              \
0164 })
0165 
0166 #define hybrid_tuner_report_instance_count(state)           \
0167 ({                                  \
0168     int __ret = 0;                          \
0169     if (state)                          \
0170         __ret = state->i2c_props.count;             \
0171     __ret;                              \
0172 })
0173 
0174 #endif /* __TUNER_I2C_H__ */