162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci tuner-i2c.h - i2c interface for different tuners 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci*/ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef __TUNER_I2C_H__ 1062306a36Sopenharmony_ci#define __TUNER_I2C_H__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct tuner_i2c_props { 1662306a36Sopenharmony_ci u8 addr; 1762306a36Sopenharmony_ci struct i2c_adapter *adap; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci /* used for tuner instance management */ 2062306a36Sopenharmony_ci int count; 2162306a36Sopenharmony_ci char *name; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, 2562306a36Sopenharmony_ci unsigned char *buf, int len) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct i2c_msg msg = { .addr = props->addr, .flags = 0, 2862306a36Sopenharmony_ci .buf = buf, .len = len }; 2962306a36Sopenharmony_ci int ret = i2c_transfer(props->adap, &msg, 1); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci return (ret == 1) ? len : ret; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, 3562306a36Sopenharmony_ci unsigned char *buf, int len) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, 3862306a36Sopenharmony_ci .buf = buf, .len = len }; 3962306a36Sopenharmony_ci int ret = i2c_transfer(props->adap, &msg, 1); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return (ret == 1) ? len : ret; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, 4562306a36Sopenharmony_ci unsigned char *obuf, int olen, 4662306a36Sopenharmony_ci unsigned char *ibuf, int ilen) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, 4962306a36Sopenharmony_ci .buf = obuf, .len = olen }, 5062306a36Sopenharmony_ci { .addr = props->addr, .flags = I2C_M_RD, 5162306a36Sopenharmony_ci .buf = ibuf, .len = ilen } }; 5262306a36Sopenharmony_ci int ret = i2c_transfer(props->adap, msg, 2); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return (ret == 2) ? ilen : ret; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Callers must declare as a global for the module: 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * static LIST_HEAD(hybrid_tuner_instance_list); 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * hybrid_tuner_instance_list should be the third argument 6262306a36Sopenharmony_ci * passed into hybrid_tuner_request_state(). 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * state structure must contain the following: 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * struct list_head hybrid_tuner_instance_list; 6762306a36Sopenharmony_ci * struct tuner_i2c_props i2c_props; 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * hybrid_tuner_instance_list (both within state structure and globally) 7062306a36Sopenharmony_ci * is only required if the driver is using hybrid_tuner_request_state 7162306a36Sopenharmony_ci * and hybrid_tuner_release_state to manage state sharing between 7262306a36Sopenharmony_ci * multiple instances of hybrid tuners. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ 7662306a36Sopenharmony_ci printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ 7762306a36Sopenharmony_ci i2cprops.adap ? \ 7862306a36Sopenharmony_ci i2c_adapter_id(i2cprops.adap) : -1, \ 7962306a36Sopenharmony_ci i2cprops.addr, ##arg); \ 8062306a36Sopenharmony_ci } while (0) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* TO DO: convert all callers of these macros to pass in 8362306a36Sopenharmony_ci * struct tuner_i2c_props, then remove the macro wrappers */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define __tuner_warn(i2cprops, fmt, arg...) do { \ 8662306a36Sopenharmony_ci tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ 8762306a36Sopenharmony_ci } while (0) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define __tuner_info(i2cprops, fmt, arg...) do { \ 9062306a36Sopenharmony_ci tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ 9162306a36Sopenharmony_ci } while (0) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define __tuner_err(i2cprops, fmt, arg...) do { \ 9462306a36Sopenharmony_ci tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ 9562306a36Sopenharmony_ci } while (0) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define __tuner_dbg(i2cprops, fmt, arg...) do { \ 9862306a36Sopenharmony_ci if ((debug)) \ 9962306a36Sopenharmony_ci tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ 10062306a36Sopenharmony_ci } while (0) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) 10362306a36Sopenharmony_ci#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) 10462306a36Sopenharmony_ci#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) 10562306a36Sopenharmony_ci#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/****************************************************************************/ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* The return value of hybrid_tuner_request_state indicates the number of 11062306a36Sopenharmony_ci * instances using this tuner object. 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * 0 - no instances, indicates an error - kzalloc must have failed 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * 1 - one instance, indicates that the tuner object was created successfully 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * 2 (or more) instances, indicates that an existing tuner object was found 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ 12062306a36Sopenharmony_ci({ \ 12162306a36Sopenharmony_ci int __ret = 0; \ 12262306a36Sopenharmony_ci list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ 12362306a36Sopenharmony_ci if (((i2cadap) && (state->i2c_props.adap)) && \ 12462306a36Sopenharmony_ci ((i2c_adapter_id(state->i2c_props.adap) == \ 12562306a36Sopenharmony_ci i2c_adapter_id(i2cadap)) && \ 12662306a36Sopenharmony_ci (i2caddr == state->i2c_props.addr))) { \ 12762306a36Sopenharmony_ci __tuner_info(state->i2c_props, \ 12862306a36Sopenharmony_ci "attaching existing instance\n"); \ 12962306a36Sopenharmony_ci state->i2c_props.count++; \ 13062306a36Sopenharmony_ci __ret = state->i2c_props.count; \ 13162306a36Sopenharmony_ci break; \ 13262306a36Sopenharmony_ci } \ 13362306a36Sopenharmony_ci } \ 13462306a36Sopenharmony_ci if (0 == __ret) { \ 13562306a36Sopenharmony_ci state = kzalloc(sizeof(type), GFP_KERNEL); \ 13662306a36Sopenharmony_ci if (!state) { \ 13762306a36Sopenharmony_ci __ret = -ENOMEM; \ 13862306a36Sopenharmony_ci goto __fail; \ 13962306a36Sopenharmony_ci } \ 14062306a36Sopenharmony_ci state->i2c_props.addr = i2caddr; \ 14162306a36Sopenharmony_ci state->i2c_props.adap = i2cadap; \ 14262306a36Sopenharmony_ci state->i2c_props.name = devname; \ 14362306a36Sopenharmony_ci __tuner_info(state->i2c_props, \ 14462306a36Sopenharmony_ci "creating new instance\n"); \ 14562306a36Sopenharmony_ci list_add_tail(&state->hybrid_tuner_instance_list, &list);\ 14662306a36Sopenharmony_ci state->i2c_props.count++; \ 14762306a36Sopenharmony_ci __ret = state->i2c_props.count; \ 14862306a36Sopenharmony_ci } \ 14962306a36Sopenharmony_ci__fail: \ 15062306a36Sopenharmony_ci __ret; \ 15162306a36Sopenharmony_ci}) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define hybrid_tuner_release_state(state) \ 15462306a36Sopenharmony_ci({ \ 15562306a36Sopenharmony_ci int __ret; \ 15662306a36Sopenharmony_ci state->i2c_props.count--; \ 15762306a36Sopenharmony_ci __ret = state->i2c_props.count; \ 15862306a36Sopenharmony_ci if (!state->i2c_props.count) { \ 15962306a36Sopenharmony_ci __tuner_info(state->i2c_props, "destroying instance\n");\ 16062306a36Sopenharmony_ci list_del(&state->hybrid_tuner_instance_list); \ 16162306a36Sopenharmony_ci kfree(state); \ 16262306a36Sopenharmony_ci } \ 16362306a36Sopenharmony_ci __ret; \ 16462306a36Sopenharmony_ci}) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define hybrid_tuner_report_instance_count(state) \ 16762306a36Sopenharmony_ci({ \ 16862306a36Sopenharmony_ci int __ret = 0; \ 16962306a36Sopenharmony_ci if (state) \ 17062306a36Sopenharmony_ci __ret = state->i2c_props.count; \ 17162306a36Sopenharmony_ci __ret; \ 17262306a36Sopenharmony_ci}) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#endif /* __TUNER_I2C_H__ */ 175