~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/firmware/sigma.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Load Analog Devices SigmaStudio firmware files
 
3
 *
 
4
 * Copyright 2009-2011 Analog Devices Inc.
 
5
 *
 
6
 * Licensed under the GPL-2 or later.
 
7
 */
 
8
 
 
9
#include <linux/crc32.h>
 
10
#include <linux/delay.h>
 
11
#include <linux/firmware.h>
 
12
#include <linux/kernel.h>
 
13
#include <linux/i2c.h>
 
14
#include <linux/sigma.h>
 
15
 
 
16
/* Return: 0==OK, <0==error, =1 ==no more actions */
 
17
static int
 
18
process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
 
19
{
 
20
        struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
 
21
        size_t len = sigma_action_len(sa);
 
22
        int ret = 0;
 
23
 
 
24
        pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
 
25
                sa->instr, sa->addr, len);
 
26
 
 
27
        switch (sa->instr) {
 
28
        case SIGMA_ACTION_WRITEXBYTES:
 
29
        case SIGMA_ACTION_WRITESINGLE:
 
30
        case SIGMA_ACTION_WRITESAFELOAD:
 
31
                if (ssfw->fw->size < ssfw->pos + len)
 
32
                        return -EINVAL;
 
33
                ret = i2c_master_send(client, (void *)&sa->addr, len);
 
34
                if (ret < 0)
 
35
                        return -EINVAL;
 
36
                break;
 
37
 
 
38
        case SIGMA_ACTION_DELAY:
 
39
                ret = 0;
 
40
                udelay(len);
 
41
                len = 0;
 
42
                break;
 
43
 
 
44
        case SIGMA_ACTION_END:
 
45
                return 1;
 
46
 
 
47
        default:
 
48
                return -EINVAL;
 
49
        }
 
50
 
 
51
        /* when arrive here ret=0 or sent data */
 
52
        ssfw->pos += sigma_action_size(sa, len);
 
53
        return ssfw->pos == ssfw->fw->size;
 
54
}
 
55
 
 
56
static int
 
57
process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
 
58
{
 
59
        pr_debug("%s: processing %p\n", __func__, ssfw);
 
60
 
 
61
        while (1) {
 
62
                int ret = process_sigma_action(client, ssfw);
 
63
                pr_debug("%s: action returned %i\n", __func__, ret);
 
64
                if (ret == 1)
 
65
                        return 0;
 
66
                else if (ret)
 
67
                        return ret;
 
68
        }
 
69
}
 
70
 
 
71
int process_sigma_firmware(struct i2c_client *client, const char *name)
 
72
{
 
73
        int ret;
 
74
        struct sigma_firmware_header *ssfw_head;
 
75
        struct sigma_firmware ssfw;
 
76
        const struct firmware *fw;
 
77
        u32 crc;
 
78
 
 
79
        pr_debug("%s: loading firmware %s\n", __func__, name);
 
80
 
 
81
        /* first load the blob */
 
82
        ret = request_firmware(&fw, name, &client->dev);
 
83
        if (ret) {
 
84
                pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
 
85
                return ret;
 
86
        }
 
87
        ssfw.fw = fw;
 
88
 
 
89
        /* then verify the header */
 
90
        ret = -EINVAL;
 
91
        if (fw->size < sizeof(*ssfw_head))
 
92
                goto done;
 
93
 
 
94
        ssfw_head = (void *)fw->data;
 
95
        if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic)))
 
96
                goto done;
 
97
 
 
98
        crc = crc32(0, fw->data, fw->size);
 
99
        pr_debug("%s: crc=%x\n", __func__, crc);
 
100
        if (crc != ssfw_head->crc)
 
101
                goto done;
 
102
 
 
103
        ssfw.pos = sizeof(*ssfw_head);
 
104
 
 
105
        /* finally process all of the actions */
 
106
        ret = process_sigma_actions(client, &ssfw);
 
107
 
 
108
 done:
 
109
        release_firmware(fw);
 
110
 
 
111
        pr_debug("%s: loaded %s\n", __func__, name);
 
112
 
 
113
        return ret;
 
114
}
 
115
EXPORT_SYMBOL(process_sigma_firmware);