1 | /* $NetBSD: tvpll.c,v 1.6 2015/03/07 14:16:51 jmcneill Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2008, 2011 Jonathan A. Kollasch |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: tvpll.c,v 1.6 2015/03/07 14:16:51 jmcneill Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/systm.h> |
34 | #include <sys/device.h> |
35 | #include <sys/kmem.h> |
36 | #include <sys/syslog.h> |
37 | #include <sys/module.h> |
38 | |
39 | #include <dev/dtv/dtvio.h> |
40 | #include <dev/i2c/i2cvar.h> |
41 | #include <dev/i2c/tvpllvar.h> |
42 | |
43 | struct tvpll { |
44 | device_t parent; |
45 | i2c_tag_t tag; |
46 | i2c_addr_t addr; |
47 | const struct tvpll_data * pll; |
48 | uint32_t frequency; |
49 | }; |
50 | |
51 | static uint32_t tvpll_algo(struct tvpll *, uint8_t *, |
52 | const struct dvb_frontend_parameters *, uint32_t *); |
53 | |
54 | struct tvpll * |
55 | tvpll_open(device_t parent, i2c_tag_t t, i2c_addr_t a, struct tvpll_data *p) |
56 | { |
57 | struct tvpll *tvpll; |
58 | |
59 | tvpll = kmem_alloc(sizeof(struct tvpll), KM_SLEEP); |
60 | if (tvpll == NULL) |
61 | return NULL; |
62 | |
63 | tvpll->tag = t; |
64 | tvpll->addr = a; |
65 | |
66 | tvpll->pll = p; |
67 | |
68 | if (tvpll->pll->initdata) { |
69 | iic_acquire_bus(tvpll->tag, I2C_F_POLL); |
70 | (void)iic_exec(tvpll->tag, I2C_OP_WRITE_WITH_STOP, tvpll->addr, |
71 | &tvpll->pll->initdata[1], tvpll->pll->initdata[0], |
72 | NULL, 0, I2C_F_POLL); |
73 | iic_release_bus(tvpll->tag, I2C_F_POLL); |
74 | } |
75 | |
76 | device_printf(parent, "tvpll: %s\n" , tvpll->pll->name); |
77 | |
78 | return tvpll; |
79 | } |
80 | |
81 | void |
82 | tvpll_close(struct tvpll *tvpll) |
83 | { |
84 | kmem_free(tvpll, sizeof(*tvpll)); |
85 | } |
86 | |
87 | static uint32_t |
88 | tvpll_algo(struct tvpll *tvpll, uint8_t *b, |
89 | const struct dvb_frontend_parameters *p, uint32_t *fr) |
90 | { |
91 | const struct tvpll_data *pll; |
92 | uint32_t d; |
93 | int i; |
94 | |
95 | pll = tvpll->pll; |
96 | |
97 | if(p->frequency != 0 && |
98 | (p->frequency < pll->min || p->frequency > pll->max)) |
99 | return 0; |
100 | |
101 | for(i = 0; i < pll->count; i++) { |
102 | if (p->frequency > pll->entries[i].limit) |
103 | continue; |
104 | else |
105 | break; |
106 | } |
107 | |
108 | if ( i >= pll->count) |
109 | return EINVAL; |
110 | |
111 | d = (p->frequency + pll->iffreq) / pll->entries[i].stepsize; |
112 | |
113 | b[0] = (d >> 8) & 0xff; |
114 | b[1] = (d >> 0) & 0xff; |
115 | b[2] = pll->entries[i].config; |
116 | b[3] = pll->entries[i].cb; |
117 | b[4] = pll->entries[i].aux; |
118 | |
119 | *fr = (d * pll->entries[i].stepsize) - pll->iffreq; |
120 | |
121 | log(LOG_DEBUG, "pllw %d %02x %02x %02x %02x %02x\n" , *fr, b[0], b[1], b[2], b[3], b[4]); |
122 | return 0; |
123 | } |
124 | |
125 | int |
126 | tvpll_tune_dtv(struct tvpll *tvpll, |
127 | const struct dvb_frontend_parameters *params) |
128 | { |
129 | int rv; |
130 | uint32_t fr; |
131 | uint8_t b[5], ab[2]; |
132 | |
133 | fr = 0; |
134 | |
135 | if((rv = tvpll_algo(tvpll, b, params, &fr)) != 0) |
136 | return rv; |
137 | |
138 | iic_acquire_bus(tvpll->tag, I2C_F_POLL); |
139 | /* gate ctrl? */ |
140 | if (b[4] != TVPLL_IGNORE_AUX) { |
141 | ab[0] = b[2] | 0x18; |
142 | ab[1] = b[4]; |
143 | rv = iic_exec(tvpll->tag, I2C_OP_WRITE_WITH_STOP, tvpll->addr, ab, 2, NULL, 0, I2C_F_POLL); |
144 | } |
145 | rv = iic_exec(tvpll->tag, I2C_OP_WRITE_WITH_STOP, tvpll->addr, b, 4, NULL, 0, I2C_F_POLL); |
146 | iic_release_bus(tvpll->tag, I2C_F_POLL); |
147 | |
148 | if (rv != 0) |
149 | printf("%s\n" , __func__); |
150 | |
151 | tvpll->frequency = fr; |
152 | |
153 | return rv; |
154 | } |
155 | |
156 | MODULE(MODULE_CLASS_DRIVER, tvpll, "i2cexec" ); |
157 | |
158 | static int |
159 | tvpll_modcmd(modcmd_t cmd, void *opaque) |
160 | { |
161 | if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI) |
162 | return 0; |
163 | return ENOTTY; |
164 | } |
165 | |