1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Driver for LNB supply and control IC LNBH25
7 * Copyright (C) 2014 NetUP Inc.
8 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
9 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/string.h>
15 #include <linux/slab.h>
17 #include <media/dvb_frontend.h>
21 * struct lnbh25_priv - LNBH25 driver private data
22 * @i2c: pointer to the I2C adapter structure
23 * @i2c_address: I2C address of LNBH25 SEC chip
24 * @config: Registers configuration:
25 * offset 0: 1st register address, always 0x02 (DATA1)
26 * offset 1: DATA1 register value
27 * offset 2: DATA2 register value
30 struct i2c_adapter
*i2c
;
35 #define LNBH25_STATUS_OFL 0x1
36 #define LNBH25_STATUS_VMON 0x4
37 #define LNBH25_VSEL_13 0x03
38 #define LNBH25_VSEL_18 0x0a
40 static int lnbh25_read_vmon(struct lnbh25_priv
*priv
)
45 struct i2c_msg msg
[2] = {
47 .addr
= priv
->i2c_address
,
52 .addr
= priv
->i2c_address
,
54 .len
= sizeof(status
),
59 for (i
= 0; i
< 2; i
++) {
60 ret
= i2c_transfer(priv
->i2c
, &msg
[i
], 1);
61 if (ret
>= 0 && ret
!= 1)
64 dev_dbg(&priv
->i2c
->dev
,
65 "%s(): I2C transfer %d failed (%d)\n",
70 dev_dbg(&priv
->i2c
->dev
, "%s(): %*ph\n",
71 __func__
, (int) sizeof(status
), status
);
72 if ((status
[0] & (LNBH25_STATUS_OFL
| LNBH25_STATUS_VMON
)) != 0) {
73 dev_err(&priv
->i2c
->dev
,
74 "%s(): voltage in failure state, status reg 0x%x\n",
81 static int lnbh25_set_voltage(struct dvb_frontend
*fe
,
82 enum fe_sec_voltage voltage
)
87 struct lnbh25_priv
*priv
= fe
->sec_priv
;
88 struct i2c_msg msg
= {
89 .addr
= priv
->i2c_address
,
91 .len
= sizeof(priv
->config
),
101 data1_reg
= LNBH25_VSEL_13
;
105 data1_reg
= LNBH25_VSEL_18
;
111 priv
->config
[1] = data1_reg
;
112 dev_dbg(&priv
->i2c
->dev
,
113 "%s(): %s, I2C 0x%x write [ %02x %02x %02x ]\n",
114 __func__
, vsel
, priv
->i2c_address
,
115 priv
->config
[0], priv
->config
[1], priv
->config
[2]);
116 ret
= i2c_transfer(priv
->i2c
, &msg
, 1);
117 if (ret
>= 0 && ret
!= 1)
120 dev_err(&priv
->i2c
->dev
, "%s(): I2C transfer error (%d)\n",
124 if (voltage
!= SEC_VOLTAGE_OFF
) {
126 ret
= lnbh25_read_vmon(priv
);
134 static void lnbh25_release(struct dvb_frontend
*fe
)
136 struct lnbh25_priv
*priv
= fe
->sec_priv
;
138 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
139 lnbh25_set_voltage(fe
, SEC_VOLTAGE_OFF
);
144 struct dvb_frontend
*lnbh25_attach(struct dvb_frontend
*fe
,
145 struct lnbh25_config
*cfg
,
146 struct i2c_adapter
*i2c
)
148 struct lnbh25_priv
*priv
;
150 dev_dbg(&i2c
->dev
, "%s()\n", __func__
);
151 priv
= kzalloc(sizeof(struct lnbh25_priv
), GFP_KERNEL
);
154 priv
->i2c_address
= (cfg
->i2c_address
>> 1);
156 priv
->config
[0] = 0x02;
157 priv
->config
[1] = 0x00;
158 priv
->config
[2] = cfg
->data2_config
;
160 if (lnbh25_set_voltage(fe
, SEC_VOLTAGE_OFF
)) {
162 "%s(): no LNBH25 found at I2C addr 0x%02x\n",
163 __func__
, priv
->i2c_address
);
169 fe
->ops
.release_sec
= lnbh25_release
;
170 fe
->ops
.set_voltage
= lnbh25_set_voltage
;
172 dev_info(&i2c
->dev
, "%s(): attached at I2C addr 0x%02x\n",
173 __func__
, priv
->i2c_address
);
176 EXPORT_SYMBOL_GPL(lnbh25_attach
);
178 MODULE_DESCRIPTION("ST LNBH25 driver");
179 MODULE_AUTHOR("info@netup.ru");
180 MODULE_LICENSE("GPL");