summaryrefslogtreecommitdiff
path: root/io-module/mtac_pulse.c
blob: dae4fa66cbe1a4ed26446fae9bf5f34c3e350290 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**********************************************************************
 * COPYRIGHT 2012-2018 CONNECTED DEVELOPMENT, LLC
 *
 * ALL RIGHTS RESERVED BY AND FOR THE EXCLUSIVE BENEFIT OF
 * CONNECTED DEVELOPMENT, LLC.
 *
 * CONNECTED DEVELOPMENT, LLC - CONFIDENTIAL AND PROPRIETARY
 * INFORMATION AND/OR TRADE SECRET.
 *
 * NOTICE: ALL CODE, PROGRAM, INFORMATION, SCRIPT, INSTRUCTION,
 * DATA, AND COMMENT HEREIN IS AND SHALL REMAIN THE CONFIDENTIAL
 * INFORMATION AND PROPERTY OF CONNECTED DEVELOPMENT, LLC.
 * USE AND DISCLOSURE THEREOF, EXCEPT AS STRICTLY AUTHORIZED IN A
 * WRITTEN AGREEMENT SIGNED BY CONNECTED DEVELOPMENT, LLC IS PROHIBITED.
 *
 ***********************************************************************/

static char* pulse_gpio_pin_name_by_attr_name(const char *name, int port) {
    switch (port) {
    case port_1:
        if (!strcmp(name, "reset")) {
            return "ap1-reset";
        } else if (!strcmp(name, "auto-boot")) {
            return "ap1-gpio1";
        } else {
            log_error("attirbute name [%s] is invalid for pulse in port %d",
                    name, port);
            return "";
        }

    case port_2:
        if (!strcmp(name, "reset")) {
            return "ap2-reset";
        } else if (!strcmp(name, "auto-boot")) {
            return "ap2-gpio1";
        } else {
            log_error("attirbute name [%s] is invalid for pulse in port %d",
                    name, port);
            return "";
        }
    }
}

// 1 reset
// 1 auto-boot
// 1 vendor-id
// 1 product-id
// 1 device-id
// 1 hw-version
// NULL
static size_t ap_pulse_attrs_size = 7;

static bool pulse_setup(enum ap port) {
    int i;
    int port_index = port - 1;
    int index = 0;
    int count = 0;
    int ret;
    char buf[32];
    struct kobj_attribute *attr;
    struct attribute **attrs;

    log_info("loading pulse accessory card in port %d", port);

    sprintf(buf, "ap%d", port);
    ap_subdirs[port_index] = kobject_create_and_add(buf,
            &mts_io_platform_device->dev.kobj);
    if (!ap_subdirs[port_index]) {
        log_error("kobject_create_and_add in port %d failed", port);
        return false;
    }

    // create the link to the apX directory this card is in
    // if we're in the first slot, we get plain "pulse"
    // if we're in a different slot, we might need to use "pulse-2" to differentiate
    if (port > 1) {
        for (i = 1; i < port; i++) {
            if (port_info[i - 1]) {
                if (strstr(port_info[i - 1]->product_id,
                        PRODUCT_ID_MTAC_PULSE)) {
                    count++;
                }
            }
        }
    }
    if (count > 0) {
        sprintf(buf, "pulse-%d", count + 1);
    } else {
        sprintf(buf, "pulse");
    }
    ret = sysfs_create_link(ap_subdirs[port_index]->parent,
            ap_subdirs[port_index], buf);
    if (ret) {
        log_error("failed to link [%s] to [%s], %d", buf,
                ap_subdirs[port_index]->name, ret);
    } else {
        log_info("created link [%s] to [%s], success:%d", buf,
                ap_subdirs[port_index]->name, ret);
    }

    attrs = kzalloc(sizeof(struct attribute *) * ap_pulse_attrs_size,
            GFP_KERNEL);
    if (!attrs) {
        log_error("failed to allocate attribute space for port %d", port);
        return false;
    }

    sprintf(buf, "reset");
    attr = create_attribute(buf, MTS_ATTR_MODE_RW);
    if (!attr) {
        log_error("failed to create attribute [%s] for pulse in port %d", buf,
                port);
        kfree(attrs);
        return false;
    }
    attr->show = mts_attr_show_ap_gpio_pin;
    attr->store = mts_attr_store_ap_gpio_pin;
    attrs[index++] = &attr->attr;

    sprintf(buf, "auto-boot");
    attr = create_attribute(buf, MTS_ATTR_MODE_RW);
    if (!attr) {
        log_error("failed to create attribute [%s] for pulse in port %d", buf,
                port);
        kfree(attrs);
        return false;
    }
    attr->show = mts_attr_show_ap_gpio_pin;
    attr->store = mts_attr_store_ap_gpio_pin;
    attrs[index++] = &attr->attr;

    // add attributes for eeprom contents
    if (!ap_add_product_info_attributes(port, MTAC_PULSE_1_0, attrs, &index)) {
        log_error("failed to add product info attributes for pulse in port %d",
                port);
        return false;
    }

    attrs[index] = NULL;

    ap_attr_groups[port_index].attrs = attrs;
    if (sysfs_create_group(ap_subdirs[port_index],
            &ap_attr_groups[port_index])) {
        log_error("sysfs_create_group failed for pulse in port %d", port);
        return false;
    }

    /* override ap_reset output mode to open drain */
    int res;
    if (port == 1) {
        res = gpio_request_one(AT91_PIN_PB12, GPIOF_OUT_INIT_HIGH | GPIOF_OPEN_DRAIN, "ap1-reset");
    } else {
        res = gpio_request_one(AT91_PIN_PB13, GPIOF_OUT_INIT_HIGH | GPIOF_OPEN_DRAIN, "ap2-reset");
    }
    if (res != 0)
    {
        log_error("failed to change ap%d_reset to open drain output", port);
    }

    return true;
}

static bool pulse_teardown(enum ap port) {
    int i;
    int port_index = port - 1;
    struct attribute **attrs = ap_attr_groups[port_index].attrs;

    log_info("unloading pulse accessory card in port %d", port);

    if (attrs) {
        // clean up allocated memory for attributes
        for (i = 0; i < ap_pulse_attrs_size; i++) {
            if (attrs[i]) {
                if (attrs[i]->name)
                    kfree(attrs[i]->name);

                kfree(attrs[i]);
            }
        }

        kfree(attrs);
    }
    // clean up our "apX/" kobject if it exists
    if (ap_subdirs[port_index]) {
        kobject_put(ap_subdirs[port_index]);
    }

    return true;
}

bool set_pulse_info(struct ap_info *info) {
    snprintf(info->product_id, 32, "%s", PRODUCT_ID_MTAC_PULSE);
    info->setup = &pulse_setup;
    info->teardown = &pulse_teardown;
    info->gpio_pin_name_by_attr_name = &pulse_gpio_pin_name_by_attr_name;

    return true;
}