summaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/otg_fsm.c
blob: d9dfaa3cf40c43e70da0c48e41803083ec9e6bc9 (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
/*
 * otg_fsm.c - ChipIdea USB IP core OTG FSM driver
 *
 * Copyright (C) 2014 Freescale Semiconductor, Inc.
 *
 * Author: Jun Li
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/*
 * This file mainly handles OTG fsm, it includes OTG fsm operations
 * for HNP and SRP.
 */

#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>

#include "ci.h"
#include "bits.h"
#include "otg.h"
#include "otg_fsm.h"

int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
{
	struct usb_otg *otg;

	otg = devm_kzalloc(ci->dev,
			sizeof(struct usb_otg), GFP_KERNEL);
	if (!otg) {
		dev_err(ci->dev,
		"Failed to allocate usb_otg structure for ci hdrc otg!\n");
		return -ENOMEM;
	}

	otg->phy = ci->transceiver;
	otg->gadget = &ci->gadget;
	ci->fsm.otg = otg;
	ci->transceiver->otg = ci->fsm.otg;
	ci->fsm.power_up = 1;
	ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
	ci->transceiver->state = OTG_STATE_UNDEFINED;

	mutex_init(&ci->fsm.lock);

	/* Enable A vbus valid irq */
	hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE);

	if (ci->fsm.id) {
		ci->fsm.b_ssend_srp =
			hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1;
		ci->fsm.b_sess_vld =
			hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0;
		/* Enable BSV irq */
		hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE);
	}

	return 0;
}