diff options
author | Kozlov Sergey <serjk@netup.ru> | 2015-07-28 10:33:02 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-08-11 13:59:05 -0400 |
commit | e025273b86fb4a6440192b809e05332777c3faa5 (patch) | |
tree | 6ca9691d4c4294e1f327b84df59af24977d1968c /drivers/media | |
parent | dacf9ce80b41667abb51a2a751a2dfe30e1f9a2b (diff) |
[media] lnbh25: LNBH25 SEC controller driver
Add DVB SEC frontend driver for STM LNBH25PQR chip.
[mchehab@osg.samsung.com: fix merge conflict:
fe_sec_voltage_t should not be used in kernelspace anymore.
instead, it should use enum fe_sec_voltage]
Signed-off-by: Kozlov Sergey <serjk@netup.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb-frontends/Kconfig | 8 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/lnbh25.c | 189 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/lnbh25.h | 56 |
4 files changed, 254 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index ec628c482cdf..82b21b92f33b 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig | |||
@@ -713,6 +713,14 @@ comment "SEC control devices for DVB-S" | |||
713 | 713 | ||
714 | source "drivers/media/dvb-frontends/drx39xyj/Kconfig" | 714 | source "drivers/media/dvb-frontends/drx39xyj/Kconfig" |
715 | 715 | ||
716 | config DVB_LNBH25 | ||
717 | tristate "LNBH25 SEC controller" | ||
718 | depends on DVB_CORE && I2C | ||
719 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
720 | help | ||
721 | An SEC control chip. | ||
722 | Say Y when you want to support this chip. | ||
723 | |||
716 | config DVB_LNBP21 | 724 | config DVB_LNBP21 |
717 | tristate "LNBP21/LNBH24 SEC controllers" | 725 | tristate "LNBP21/LNBH24 SEC controllers" |
718 | depends on DVB_CORE && I2C | 726 | depends on DVB_CORE && I2C |
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 0a1bf69cb79a..07d962a29763 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile | |||
@@ -57,6 +57,7 @@ obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o | |||
57 | obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o | 57 | obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o |
58 | obj-$(CONFIG_DVB_LG2160) += lg2160.o | 58 | obj-$(CONFIG_DVB_LG2160) += lg2160.o |
59 | obj-$(CONFIG_DVB_CX24123) += cx24123.o | 59 | obj-$(CONFIG_DVB_CX24123) += cx24123.o |
60 | obj-$(CONFIG_DVB_LNBH25) += lnbh25.o | ||
60 | obj-$(CONFIG_DVB_LNBP21) += lnbp21.o | 61 | obj-$(CONFIG_DVB_LNBP21) += lnbp21.o |
61 | obj-$(CONFIG_DVB_LNBP22) += lnbp22.o | 62 | obj-$(CONFIG_DVB_LNBP22) += lnbp22.o |
62 | obj-$(CONFIG_DVB_ISL6405) += isl6405.o | 63 | obj-$(CONFIG_DVB_ISL6405) += isl6405.o |
diff --git a/drivers/media/dvb-frontends/lnbh25.c b/drivers/media/dvb-frontends/lnbh25.c new file mode 100644 index 000000000000..ef3021e964be --- /dev/null +++ b/drivers/media/dvb-frontends/lnbh25.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * lnbh25.c | ||
3 | * | ||
4 | * Driver for LNB supply and control IC LNBH25 | ||
5 | * | ||
6 | * Copyright (C) 2014 NetUP Inc. | ||
7 | * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> | ||
8 | * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include "dvb_frontend.h" | ||
27 | #include "lnbh25.h" | ||
28 | |||
29 | /** | ||
30 | * struct lnbh25_priv - LNBH25 driver private data | ||
31 | * @i2c: pointer to the I2C adapter structure | ||
32 | * @i2c_address: I2C address of LNBH25 SEC chip | ||
33 | * @config: Registers configuration: | ||
34 | * offset 0: 1st register address, always 0x02 (DATA1) | ||
35 | * offset 1: DATA1 register value | ||
36 | * offset 2: DATA2 register value | ||
37 | */ | ||
38 | struct lnbh25_priv { | ||
39 | struct i2c_adapter *i2c; | ||
40 | u8 i2c_address; | ||
41 | u8 config[3]; | ||
42 | }; | ||
43 | |||
44 | #define LNBH25_STATUS_OFL 0x1 | ||
45 | #define LNBH25_STATUS_VMON 0x4 | ||
46 | #define LNBH25_VSEL_13 0x03 | ||
47 | #define LNBH25_VSEL_18 0x0a | ||
48 | |||
49 | static int lnbh25_read_vmon(struct lnbh25_priv *priv) | ||
50 | { | ||
51 | int i, ret; | ||
52 | u8 addr = 0x00; | ||
53 | u8 status[6]; | ||
54 | struct i2c_msg msg[2] = { | ||
55 | { | ||
56 | .addr = priv->i2c_address, | ||
57 | .flags = 0, | ||
58 | .len = 1, | ||
59 | .buf = &addr | ||
60 | }, { | ||
61 | .addr = priv->i2c_address, | ||
62 | .flags = I2C_M_RD, | ||
63 | .len = sizeof(status), | ||
64 | .buf = status | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | for (i = 0; i < 2; i++) { | ||
69 | ret = i2c_transfer(priv->i2c, &msg[i], 1); | ||
70 | if (ret >= 0 && ret != 1) | ||
71 | ret = -EIO; | ||
72 | if (ret < 0) { | ||
73 | dev_dbg(&priv->i2c->dev, | ||
74 | "%s(): I2C transfer %d failed (%d)\n", | ||
75 | __func__, i, ret); | ||
76 | return ret; | ||
77 | } | ||
78 | } | ||
79 | print_hex_dump_bytes("lnbh25_read_vmon: ", | ||
80 | DUMP_PREFIX_OFFSET, status, sizeof(status)); | ||
81 | if ((status[0] & (LNBH25_STATUS_OFL | LNBH25_STATUS_VMON)) != 0) { | ||
82 | dev_err(&priv->i2c->dev, | ||
83 | "%s(): voltage in failure state, status reg 0x%x\n", | ||
84 | __func__, status[0]); | ||
85 | return -EIO; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int lnbh25_set_voltage(struct dvb_frontend *fe, | ||
91 | enum fe_sec_voltage voltage) | ||
92 | { | ||
93 | int ret; | ||
94 | u8 data1_reg; | ||
95 | const char *vsel; | ||
96 | struct lnbh25_priv *priv = fe->sec_priv; | ||
97 | struct i2c_msg msg = { | ||
98 | .addr = priv->i2c_address, | ||
99 | .flags = 0, | ||
100 | .len = sizeof(priv->config), | ||
101 | .buf = priv->config | ||
102 | }; | ||
103 | |||
104 | switch (voltage) { | ||
105 | case SEC_VOLTAGE_OFF: | ||
106 | data1_reg = 0x00; | ||
107 | vsel = "Off"; | ||
108 | break; | ||
109 | case SEC_VOLTAGE_13: | ||
110 | data1_reg = LNBH25_VSEL_13; | ||
111 | vsel = "13V"; | ||
112 | break; | ||
113 | case SEC_VOLTAGE_18: | ||
114 | data1_reg = LNBH25_VSEL_18; | ||
115 | vsel = "18V"; | ||
116 | break; | ||
117 | default: | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | priv->config[1] = data1_reg; | ||
121 | dev_dbg(&priv->i2c->dev, | ||
122 | "%s(): %s, I2C 0x%x write [ %02x %02x %02x ]\n", | ||
123 | __func__, vsel, priv->i2c_address, | ||
124 | priv->config[0], priv->config[1], priv->config[2]); | ||
125 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
126 | if (ret >= 0 && ret != 1) | ||
127 | ret = -EIO; | ||
128 | if (ret < 0) { | ||
129 | dev_err(&priv->i2c->dev, "%s(): I2C transfer error (%d)\n", | ||
130 | __func__, ret); | ||
131 | return ret; | ||
132 | } | ||
133 | if (voltage != SEC_VOLTAGE_OFF) { | ||
134 | msleep(120); | ||
135 | ret = lnbh25_read_vmon(priv); | ||
136 | } else { | ||
137 | msleep(20); | ||
138 | ret = 0; | ||
139 | } | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static void lnbh25_release(struct dvb_frontend *fe) | ||
144 | { | ||
145 | struct lnbh25_priv *priv = fe->sec_priv; | ||
146 | |||
147 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
148 | lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF); | ||
149 | kfree(fe->sec_priv); | ||
150 | fe->sec_priv = NULL; | ||
151 | } | ||
152 | |||
153 | struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe, | ||
154 | struct lnbh25_config *cfg, | ||
155 | struct i2c_adapter *i2c) | ||
156 | { | ||
157 | struct lnbh25_priv *priv; | ||
158 | |||
159 | dev_dbg(&i2c->dev, "%s()\n", __func__); | ||
160 | priv = kzalloc(sizeof(struct lnbh25_priv), GFP_KERNEL); | ||
161 | if (!priv) | ||
162 | return NULL; | ||
163 | priv->i2c_address = (cfg->i2c_address >> 1); | ||
164 | priv->i2c = i2c; | ||
165 | priv->config[0] = 0x02; | ||
166 | priv->config[1] = 0x00; | ||
167 | priv->config[2] = cfg->data2_config; | ||
168 | fe->sec_priv = priv; | ||
169 | if (lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF)) { | ||
170 | dev_err(&i2c->dev, | ||
171 | "%s(): no LNBH25 found at I2C addr 0x%02x\n", | ||
172 | __func__, priv->i2c_address); | ||
173 | kfree(priv); | ||
174 | fe->sec_priv = NULL; | ||
175 | return NULL; | ||
176 | } | ||
177 | |||
178 | fe->ops.release_sec = lnbh25_release; | ||
179 | fe->ops.set_voltage = lnbh25_set_voltage; | ||
180 | |||
181 | dev_err(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n", | ||
182 | __func__, priv->i2c_address); | ||
183 | return fe; | ||
184 | } | ||
185 | EXPORT_SYMBOL(lnbh25_attach); | ||
186 | |||
187 | MODULE_DESCRIPTION("ST LNBH25 driver"); | ||
188 | MODULE_AUTHOR("info@netup.ru"); | ||
189 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb-frontends/lnbh25.h b/drivers/media/dvb-frontends/lnbh25.h new file mode 100644 index 000000000000..69f30e21f6b3 --- /dev/null +++ b/drivers/media/dvb-frontends/lnbh25.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * lnbh25.c | ||
3 | * | ||
4 | * Driver for LNB supply and control IC LNBH25 | ||
5 | * | ||
6 | * Copyright (C) 2014 NetUP Inc. | ||
7 | * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> | ||
8 | * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #ifndef LNBH25_H | ||
22 | #define LNBH25_H | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/kconfig.h> | ||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | /* 22 kHz tone enabled. Tone output controlled by DSQIN pin */ | ||
29 | #define LNBH25_TEN 0x01 | ||
30 | /* Low power mode activated (used only with 22 kHz tone output disabled) */ | ||
31 | #define LNBH25_LPM 0x02 | ||
32 | /* DSQIN input pin is set to receive external 22 kHz TTL signal source */ | ||
33 | #define LNBH25_EXTM 0x04 | ||
34 | |||
35 | struct lnbh25_config { | ||
36 | u8 i2c_address; | ||
37 | u8 data2_config; | ||
38 | }; | ||
39 | |||
40 | #if IS_REACHABLE(CONFIG_DVB_LNBH25) | ||
41 | struct dvb_frontend *lnbh25_attach( | ||
42 | struct dvb_frontend *fe, | ||
43 | struct lnbh25_config *cfg, | ||
44 | struct i2c_adapter *i2c); | ||
45 | #else | ||
46 | static inline dvb_frontend *lnbh25_attach( | ||
47 | struct dvb_frontend *fe, | ||
48 | struct lnbh25_config *cfg, | ||
49 | struct i2c_adapter *i2c) | ||
50 | { | ||
51 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
52 | return NULL; | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | #endif | ||