Full support for Ginger Console
[linux-ginger.git] / drivers / media / video / isp / ispstat.c
blob2d0e64f5e5fda0f4860b232876f6557affdeafd8
1 /*
2 * ispstat.c
4 * STAT module for TI's OMAP3 Camera ISP
6 * Copyright (C) 2009 Texas Instruments, Inc.
8 * Contributors:
9 * Sergio Aguirre <saaguirre@ti.com>
10 * Troy Laramy
12 * This package is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 #include <linux/dma-mapping.h>
22 #include <linux/uaccess.h>
24 #include "isp.h"
26 /* Get next free buffer to write the statistics to and mark it active. */
27 struct ispstat_buffer *ispstat_buf_next(struct ispstat *stat)
29 unsigned long flags;
30 struct ispstat_buffer *found = NULL;
31 int i;
33 if (stat->active_buf)
34 do_gettimeofday(&stat->active_buf->ts);
36 spin_lock_irqsave(&stat->lock, flags);
38 if (stat->active_buf) {
39 stat->active_buf->config_counter = stat->config_counter;
40 stat->active_buf->frame_number = stat->frame_number;
43 for (i = 0; i < stat->nbufs; i++) {
44 struct ispstat_buffer *curr = &stat->buf[i];
47 * Don't select the buffer which is being copied to
48 * userspace.
50 if (curr == stat->locked_buf)
51 continue;
53 if (!found
54 || (curr->frame_number > found->frame_number
55 && (curr->frame_number - found->frame_number
56 > stat->max_frame / 2))
57 || (curr->frame_number < found->frame_number
58 && (found->frame_number - curr->frame_number
59 < stat->max_frame / 2))) {
60 found = curr;
64 stat->active_buf = found;
66 stat->frame_number++;
67 if (stat->frame_number == stat->max_frame)
68 stat->frame_number = 0;
70 spin_unlock_irqrestore(&stat->lock, flags);
72 return found;
75 /* Get buffer to userspace. */
76 static struct ispstat_buffer *ispstat_buf_find(
77 struct ispstat *stat, u32 frame_number)
79 struct ispstat_buffer *latest = NULL;
80 int i;
82 for (i = 0; i < stat->nbufs; i++) {
83 struct ispstat_buffer *curr = &stat->buf[i];
85 /* We cannot deal with the active buffer. */
86 if (curr == stat->active_buf)
87 continue;
89 /* Don't take uninitialised buffers. */
90 if (curr->frame_number == stat->max_frame)
91 continue;
93 /* Found correct number. */
94 if (curr->frame_number == frame_number) {
95 latest = curr;
96 break;
99 /* Select first buffer or a better one. */
100 if (!latest
101 || (curr->frame_number < latest->frame_number
102 && (latest->frame_number - curr->frame_number
103 > stat->max_frame / 2))
104 || (curr->frame_number > latest->frame_number
105 && (curr->frame_number - latest->frame_number
106 < stat->max_frame / 2)))
107 latest = curr;
110 return latest;
114 * ispstat_stats_available - Check for stats available of specified frame.
115 * @aewbdata: Pointer to return AE AWB statistics data
117 * Returns 0 if successful, or -1 if statistics are unavailable.
119 struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat,
120 void __user *ptr,
121 unsigned int frame_number)
123 int rval = 0;
124 unsigned long flags;
125 struct ispstat_buffer *buf;
127 spin_lock_irqsave(&stat->lock, flags);
129 buf = ispstat_buf_find(stat, frame_number);
130 if (!buf) {
131 spin_unlock_irqrestore(&stat->lock, flags);
132 return ERR_PTR(-EBUSY);
135 stat->locked_buf = buf;
137 spin_unlock_irqrestore(&stat->lock, flags);
139 rval = copy_to_user((void *)ptr,
140 buf->virt_addr,
141 stat->buf_size);
143 if (rval) {
144 dev_info(stat->dev,
145 "failed copying %d bytes of stat data\n", rval);
146 buf = ERR_PTR(-EFAULT);
147 ispstat_buf_release(stat);
150 return buf;
153 void ispstat_buf_release(struct ispstat *stat)
155 unsigned long flags;
157 spin_lock_irqsave(&stat->lock, flags);
158 stat->locked_buf = NULL;
159 spin_unlock_irqrestore(&stat->lock, flags);
162 void ispstat_bufs_free(struct ispstat *stat)
164 struct isp_device *isp = dev_get_drvdata(stat->dev);
165 int i;
167 for (i = 0; i < stat->nbufs; i++) {
168 struct ispstat_buffer *buf = &stat->buf[i];
170 if (!buf->iommu_addr)
171 continue;
173 iommu_vfree(isp->iommu, buf->iommu_addr);
174 buf->iommu_addr = 0;
177 stat->buf_alloc_size = 0;
180 int ispstat_bufs_alloc(struct ispstat *stat,
181 unsigned int size)
183 struct isp_device *isp = dev_get_drvdata(stat->dev);
184 unsigned long flags;
185 int i;
187 spin_lock_irqsave(&stat->lock, flags);
189 BUG_ON(stat->locked_buf != NULL);
191 /* Are the old buffers big enough? */
192 if (stat->buf_alloc_size >= size) {
193 for (i = 0; i < stat->nbufs; i++)
194 stat->buf[i].frame_number = stat->max_frame;
195 spin_unlock_irqrestore(&stat->lock, flags);
196 goto out;
199 if (isp->running != ISP_STOPPED) {
200 dev_info(stat->dev, "stat: trying to configure when busy\n");
201 spin_unlock_irqrestore(&stat->lock, flags);
202 return -EBUSY;
205 spin_unlock_irqrestore(&stat->lock, flags);
207 ispstat_bufs_free(stat);
209 for (i = 0; i < stat->nbufs; i++) {
210 struct ispstat_buffer *buf = &stat->buf[i];
212 buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
213 IOMMU_FLAG);
214 if (buf->iommu_addr == 0) {
215 dev_info(stat->dev, "stat: Can't acquire memory for "
216 "buffer %d\n", i);
217 ispstat_bufs_free(stat);
218 return -ENOMEM;
220 buf->virt_addr = da_to_va(isp->iommu, (u32)buf->iommu_addr);
221 buf->frame_number = stat->max_frame;
224 stat->buf_alloc_size = size;
226 out:
227 stat->buf_size = size;
228 stat->active_buf = NULL;
230 return 0;
233 int ispstat_init(struct device *dev, struct ispstat *stat,
234 unsigned int nbufs, unsigned int max_frame)
236 BUG_ON(nbufs < 2);
237 BUG_ON(max_frame < 2);
238 BUG_ON(nbufs >= max_frame);
240 memset(stat, 0, sizeof(*stat));
242 stat->buf = kcalloc(nbufs, sizeof(*stat->buf), GFP_KERNEL);
243 if (!stat->buf)
244 return -ENOMEM;
246 spin_lock_init(&stat->lock);
247 stat->nbufs = nbufs;
248 stat->dev = dev;
249 stat->max_frame = max_frame;
251 return 0;
254 void ispstat_free(struct ispstat *stat)
256 ispstat_bufs_free(stat);
257 kfree(stat->buf);