[media] smiapp: Allow using external clock from the clock framework
[deliverable/linux.git] / drivers / media / video / smiapp / smiapp-regs.c
CommitLineData
ccfc97bd
SA
1/*
2 * drivers/media/video/smiapp/smiapp-regs.c
3 *
4 * Generic driver for SMIA/SMIA++ compliant camera modules
5 *
6 * Copyright (C) 2011--2012 Nokia Corporation
7 * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
ccfc97bd
SA
25#include <linux/delay.h>
26#include <linux/i2c.h>
27
28#include "smiapp-regs.h"
29
30static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
31 uint32_t phloat)
32{
33 int32_t exp;
34 uint64_t man;
35
36 if (phloat >= 0x80000000) {
37 dev_err(&client->dev, "this is a negative number\n");
38 return 0;
39 }
40
41 if (phloat == 0x7f800000)
42 return ~0; /* Inf. */
43
44 if ((phloat & 0x7f800000) == 0x7f800000) {
45 dev_err(&client->dev, "NaN or other special number\n");
46 return 0;
47 }
48
49 /* Valid cases begin here */
50 if (phloat == 0)
51 return 0; /* Valid zero */
52
53 if (phloat > 0x4f800000)
54 return ~0; /* larger than 4294967295 */
55
56 /*
57 * Unbias exponent (note how phloat is now guaranteed to
58 * have 0 in the high bit)
59 */
60 exp = ((int32_t)phloat >> 23) - 127;
61
62 /* Extract mantissa, add missing '1' bit and it's in MHz */
63 man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
64
65 if (exp < 0)
66 man >>= -exp;
67 else
68 man <<= exp;
69
70 man >>= 23; /* Remove mantissa bias */
71
72 return man & 0xffffffff;
73}
74
75
76/*
77 * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
78 * Returns zero if successful, or non-zero otherwise.
79 */
80int smiapp_read(struct i2c_client *client, u32 reg, u32 *val)
81{
82 struct i2c_msg msg;
83 unsigned char data[4];
84 unsigned int len = (u8)(reg >> 16);
85 u16 offset = reg;
86 int r;
87
88 if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
89 && len != SMIA_REG_32BIT)
90 return -EINVAL;
91
92 msg.addr = client->addr;
93 msg.flags = 0;
94 msg.len = 2;
95 msg.buf = data;
96
97 /* high byte goes out first */
98 data[0] = (u8) (offset >> 8);
99 data[1] = (u8) offset;
100 r = i2c_transfer(client->adapter, &msg, 1);
101 if (r != 1) {
102 if (r >= 0)
103 r = -EBUSY;
104 goto err;
105 }
106
107 msg.len = len;
108 msg.flags = I2C_M_RD;
109 r = i2c_transfer(client->adapter, &msg, 1);
110 if (r != 1) {
111 if (r >= 0)
112 r = -EBUSY;
113 goto err;
114 }
115
116 *val = 0;
117 /* high byte comes first */
118 switch (len) {
119 case SMIA_REG_32BIT:
120 *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
121 data[3];
122 break;
123 case SMIA_REG_16BIT:
124 *val = (data[0] << 8) + data[1];
125 break;
126 case SMIA_REG_8BIT:
127 *val = data[0];
128 break;
129 default:
130 BUG();
131 }
132
133 if (reg & SMIA_REG_FLAG_FLOAT)
134 *val = float_to_u32_mul_1000000(client, *val);
135
136 return 0;
137
138err:
139 dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
140
141 return r;
142}
143
144/*
145 * Write to a 8/16-bit register.
146 * Returns zero if successful, or non-zero otherwise.
147 */
148int smiapp_write(struct i2c_client *client, u32 reg, u32 val)
149{
150 struct i2c_msg msg;
151 unsigned char data[6];
152 unsigned int retries;
153 unsigned int flags = reg >> 24;
154 unsigned int len = (u8)(reg >> 16);
155 u16 offset = reg;
156 int r;
157
158 if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
159 len != SMIA_REG_32BIT) || flags)
160 return -EINVAL;
161
162 msg.addr = client->addr;
163 msg.flags = 0; /* Write */
164 msg.len = 2 + len;
165 msg.buf = data;
166
167 /* high byte goes out first */
168 data[0] = (u8) (reg >> 8);
169 data[1] = (u8) (reg & 0xff);
170
171 switch (len) {
172 case SMIA_REG_8BIT:
173 data[2] = val;
174 break;
175 case SMIA_REG_16BIT:
176 data[2] = val >> 8;
177 data[3] = val;
178 break;
179 case SMIA_REG_32BIT:
180 data[2] = val >> 24;
181 data[3] = val >> 16;
182 data[4] = val >> 8;
183 data[5] = val;
184 break;
185 default:
186 BUG();
187 }
188
189 for (retries = 0; retries < 5; retries++) {
190 /*
191 * Due to unknown reason sensor stops responding. This
192 * loop is a temporaty solution until the root cause
193 * is found.
194 */
195 r = i2c_transfer(client->adapter, &msg, 1);
196 if (r == 1) {
197 if (retries)
198 dev_err(&client->dev,
199 "sensor i2c stall encountered. "
200 "retries: %d\n", retries);
201 return 0;
202 }
203
204 usleep_range(2000, 2000);
205 }
206
207 dev_err(&client->dev,
208 "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
209
210 return r;
211}
This page took 0.060616 seconds and 5 git commands to generate.