summaryrefslogtreecommitdiff
path: root/board/keyborg/master_slave.c
blob: 39f41ddddb1ee4b3961e167773cc6c7433d8916f (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
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
/* Master/slave identification */

#include "board.h"
#include "debug.h"
#include "master_slave.h"
#include "registers.h"
#include "timer.h"
#include "util.h"

#define SYNC1 (1 << 1) /* PI1 */
#define SYNC2 (1 << 2) /* PI2 */

static int is_master = -1;
static int last_sync; /* = 0 -> Low */

int master_slave_is_master(void)
{
	return is_master;
}

static int wait_sync_signal(int mask, int v, int timeout_ms)
{
	uint32_t start = get_time().val;

	while ((!!(STM32_GPIO_IDR(GPIO_I) & mask)) != v) {
		if ((get_time().val - start) >= timeout_ms * MSEC)
			return EC_ERROR_TIMEOUT;
	}
	return EC_SUCCESS;
}

int master_slave_sync(int timeout_ms)
{
	int err = EC_SUCCESS;
	last_sync ^= 1;
	if (is_master) {
		STM32_GPIO_BSRR(GPIO_I) = SYNC1 << (last_sync ? 0 : 16);
		if (wait_sync_signal(SYNC2, last_sync, timeout_ms))
			err = EC_ERROR_TIMEOUT;
	} else {
		if (wait_sync_signal(SYNC1, last_sync, timeout_ms))
			err = EC_ERROR_TIMEOUT;
		STM32_GPIO_BSRR(GPIO_I) = SYNC2 << (last_sync ? 0 : 16);
	}
	return err;
}

static int master_handshake(void)
{
	uint32_t val;
	int err;

	/* SYNC2 -> GPIO_INPUT */
	val = STM32_GPIO_CRL(GPIO_I);
	val &= ~0x00000f00;
	val |=  0x00000400;
	STM32_GPIO_CRL(GPIO_I) = val;

	err = master_slave_sync(1000);
	err |= master_slave_sync(20);
	err |= master_slave_sync(20);

	return err;
}

static int slave_handshake(void)
{
	uint32_t val;
	int err;

	/* SYNC1 -> GPIO_INPUT */
	val = STM32_GPIO_CRL(GPIO_I);
	val &= ~0x000000f0;
	val |=  0x00000040;
	STM32_GPIO_CRL(GPIO_I) = val;

	err = master_slave_sync(1000);
	err |= master_slave_sync(20);
	err |= master_slave_sync(20);

	return err;
}

static void master_slave_check(void)
{
	if (STM32_GPIO_IDR(GPIO_A) & (1 << 0) /* NSS */) {
		debug_printf("I'm slave\n");
		is_master = 0;
	} else {
		debug_printf("I'm master\n");
		is_master = 1;
	}
}

int master_slave_init(void)
{
	int handshake_err;

	master_slave_check();

	if (is_master)
		handshake_err = master_handshake();
	else
		handshake_err = slave_handshake();

	if (handshake_err != EC_SUCCESS)
		debug_printf("handshake error\n");
	else
		debug_printf("handshake done\n");

	return handshake_err;
}