/*--------------------------------------------------------------------------*
 * drivers/usb/mcd/usb_mcd_fifo.h
 * 
 * USB controller driver
 * 
 * Copyright 2005,2006,2008 Sony Corporation
 *
 * This file is part of the Inventra Controller Driver for Linux.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *---------------------------------------------------------------------------*/

#ifndef _USB_OTG_CONTROL_H_
#define _USB_OTG_CONTROL_H_

/*
 *	構造体
 */

/*
 * 列挙型：usb_otg_vbus_stat
 * Vbusの電圧状態を示す。UNKOWN=-1, OFF=0, LOW=1, SESS=2, VALID=3
 */

enum usb_otg_vbus_stat {
	USB_OTG_VBUS_STAT_UNKNOWN = -1,
	USB_OTG_VBUS_STAT_OFF = 0,
	USB_OTG_VBUS_STAT_LOW = 1,
	USB_OTG_VBUS_STAT_SESS = 2,
	USB_OTG_VBUS_STAT_VALID = 3,
};

/*
 * 列挙型：usb_otg_control_speed
 * 通信速度を示す。
 */

enum usb_otg_control_speed {
	USB_OTG_SPEED_LS,
	USB_OTG_SPEED_FS,
	USB_OTG_SPEED_HS,
};

/*
 * 列挙型：usb_otg_control_test_mode
 * 通信速度を示す。
 */

enum usb_otg_control_test_mode {
	USB_OTG_TEST_MODE_NORMAL,
	/* Gadget標準テスト */
	USB_OTG_TEST_MODE_G_PACKET,
	USB_OTG_TEST_MODE_G_K,
	USB_OTG_TEST_MODE_G_J,
	USB_OTG_TEST_MODE_G_SE0_NAK,
	/* Gadgetハード依存テスト */
	USB_OTG_TEST_MODE_G_FORCE_PACKET,	/* 強制パケット送出モード */
	/* Host標準テスト */
	USB_OTG_TEST_MODE_H_PACKET,
	USB_OTG_TEST_MODE_H_K,
	USB_OTG_TEST_MODE_H_J,
	USB_OTG_TEST_MODE_H_SE0_NAK,
	/* Hostハード依存テスト */
	USB_OTG_TEST_MODE_H_SETUP,
	USB_OTG_TEST_MODE_H_IN,
	USB_OTG_TEST_MODE_H_AS,	/* 速度無指定 */
	USB_OTG_TEST_MODE_H_LS,	/* LowSpeed */
	USB_OTG_TEST_MODE_H_FS,	/* FullSpeed */
	USB_OTG_TEST_MODE_H_HS,	/* HighSpeed */
};

/*
 * 列挙型：usb_otg_event_type
 * OTGイベントタイプを示す。
 */

enum usb_otg_event_type {
	USB_OTG_EVENT_TYPE_CID = 1,
	USB_OTG_EVENT_TYPE_VBUS,
	USB_OTG_EVENT_TYPE_VBUSERROR,
	USB_OTG_EVENT_TYPE_CON,
	USB_OTG_EVENT_TYPE_SRP,
	USB_OTG_EVENT_TYPE_RCHOST,
	USB_OTG_EVENT_TYPE_RCGADGET,
};

/*
 * 構造体：usb_otg_event_cid
 * CID値の変化を示す。
 */

struct usb_otg_event_cid {
	enum usb_otg_event_type type;
	unsigned int value;
	unsigned int port;
};

/*
 * 構造体：usb_otg_event_vbus
 * Vbusの電圧状態を示す。
 */

struct usb_otg_event_vbus {
	enum usb_otg_event_type type;
	enum usb_otg_vbus_stat vbus_stat;
	unsigned int port;
};

/*
 * 構造体：usb_otg_event_vbuserror
 * Vbusの異常を示す。
 */

struct usb_otg_event_vbuserror {
	enum usb_otg_event_type type;
};

/*
 * 構造体：usb_otg_event_con
 * Host動作時、接続相手GadgetのD+ Pullupに基づく接続切断を示す。
 */

struct usb_otg_event_con {
	enum usb_otg_event_type type;
	unsigned int value;
};

/*
 * 構造体：usb_otg_event_srp
 * a-device時、接続相手GadgetのSRPパルシングを示す。
 */

struct usb_otg_event_srp {
	enum usb_otg_event_type type;
};

/*
 * 構造体：usb_otg_event_rc
 * HNP時のRoleChangeの完了およびその成否を示す。
 */

struct usb_otg_event_rc {
	enum usb_otg_event_type type;
	unsigned int status;
};

#define USB_OTG_SUCCESS			0	/* RoleChange成功 */
#define USB_OTG_FAIL_T_B_ASE0_BRST	1	/* b-deviceのRcHost時、D+ラインの
						   Pullup OFFから3.125[ms]以内に接続相
						   手a-deviceがPullup ONをしなかった。
						 */
#define USB_OTG_FAIL_T_A_AIDL_BDIS	2	/* a-deviceのRcGadget時、バスをサスペ
						   ンドにしてから200[ms]以内に接続相手
						   b-deviceがD+ラインのPullup OFFをし
						   なかった。 */

/*
 * 共用体：usb_otg_event
 * OTGイベントを表す。ControllerにてUSBのOTGに関わるイベントを設定し、API関数
 * usb_otg_core_notifyにてCoreへ通知する。
 */

union usb_otg_event {
	enum usb_otg_event_type type;
	struct usb_otg_event_cid cid;
	struct usb_otg_event_vbus vbus;
	struct usb_otg_event_vbuserror vbuserror;
	struct usb_otg_event_con con;
	struct usb_otg_event_srp srp;
	struct usb_otg_event_rc rchost;
	struct usb_otg_event_rc rcgadget;
};

/*
 * 構造体 : usb_otg_control_port_info
 * USBポートの情報を表す。複数のUSBポートを排他的に使用する際に
 * usb_otg_control_get_port_infoにて全ポート数と現在選択されているポート番号を
 * 取得する。
 */

struct usb_otg_control_port_info {
	unsigned int nr;
	unsigned int current_port;
};

/*
 * 構造体：usb_otg_control_ops
 * OTGコントローラ操作関数を表す。各操作関数に対応するインラインマクロが
 * usb_otg_control.hに定義されており、直接これらの操作関数を使用する必要は無い。
 * これらの詳細説明は、関数説明の項目にて対応するインライン関数の定義を参照の
 * こと。
 */

struct usb_otg_control;		/* prototype */

struct usb_otg_control_ops {
	int (*get_port_info) (struct usb_otg_control *,
			      struct usb_otg_control_port_info * info);
	int (*select_port) (struct usb_otg_control *, unsigned int pn);
	int (*start_control) (struct usb_otg_control *);
	int (*stop_control) (struct usb_otg_control *);
	int (*start_gadget) (struct usb_otg_control *);
	int (*stop_gadget) (struct usb_otg_control *);
	int (*enable_rchost) (struct usb_otg_control *);
	int (*disable_rchost) (struct usb_otg_control *);
	int (*stop_rchost) (struct usb_otg_control *);
	int (*start_host) (struct usb_otg_control *);
	int (*stop_host) (struct usb_otg_control *);
	int (*start_rcgadget) (struct usb_otg_control *, unsigned int port);
	int (*stop_rcgadget) (struct usb_otg_control *, unsigned int port);
	int (*get_mode) (struct usb_otg_control *);
	int (*request_session) (struct usb_otg_control *);
	int (*set_speed) (struct usb_otg_control *,
			  enum usb_otg_control_speed speed);
	enum usb_otg_control_speed (*get_speed) (struct usb_otg_control *);
	int (*set_test_mode) (struct usb_otg_control *,
			      enum usb_otg_control_test_mode test_mode);
	enum usb_otg_control_test_mode (*get_test_mode) (struct usb_otg_control
							 *);
};

/*
 * 構造体：usb_otg_control
 * OTGコントローラを表す。要素として、OTGコントローラを操作する操作関数、周期関
 * 数およびユーザー実装関数にて使用する情報、OTGコントローラの識別情報を持つ。
 */

struct usb_otg_control {
	struct usb_otg_control_ops *ops;
	struct usb_otg_core *otg_core;
	const char *name;
	void *data;
};

/*
 * 構造体：usb_otg_core
 * OTG coreを表す。要素として、OTGコントローラをバインドとアンバインドする操作関
 * 数、USBイベントを通知する操作関数を持つ。
 */

struct usb_otg_core {
	int (*bind) (struct usb_otg_control * otg_control);
	int (*unbind) (struct usb_otg_control * otg_control);
	int (*notify) (union usb_otg_event * otg_event);
};

/*
 *	関数
 */

/*
 * 関数：usb_otg_control_register_core
 * OTG Coreをコントローラへ登録する。
 */

extern int usb_otg_control_register_core(struct usb_otg_core *otg_core);

/*
 * 関数：usb_otg_control_unregister_core
 * OTG Coreをコントローラへ登録解除する。
 */

extern int usb_otg_control_unregister_core(struct usb_otg_core *otg_core);

/*
 * 関数：usb_otg_core_notify
 * OTGコントローラからCoreへイベントを通知する。
 */

static inline int
usb_otg_core_notify(struct usb_otg_core *otg_core,
		    union usb_otg_event *otg_event)
{
	return otg_core->notify(otg_event);
}

/*
 * 関数：usb_otg_core_bind
 * OTGコントローラをCoreへバインドする。
 */

static inline int
usb_otg_core_bind(struct usb_otg_core *otg_core,
		  struct usb_otg_control *otg_control)
{
	return otg_core->bind(otg_control);
}

/*
 * 関数：usb_otg_core_unbind
 * OTGコントローラをCoreへアンバインドする。
 */

static inline int
usb_otg_core_unbind(struct usb_otg_core *otg_core,
		    struct usb_otg_control *otg_control)
{
	return otg_core->unbind(otg_control);
}

/*
 * 関数：usb_otg_control_get_port_info
 * USBポート情報を取得する。
 */

static inline int
usb_otg_control_get_port_info(struct usb_otg_control *otg_control,
			      struct usb_otg_control_port_info *info)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->get_port_info(otg_control, info);
}

/*
 * 関数：usb_otg_control_select_port
 * USBポートを選択する。
 */

static inline int
usb_otg_control_select_port(struct usb_otg_control *otg_control,
			    unsigned int pn)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->select_port(otg_control, (u32)pn);
}

/*
 * 関数：usb_otg_control_start_control
 * Controllerを開始する。
 */

static inline int
usb_otg_control_start_control(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->start_control(otg_control);
}

/*
 * 関数：usb_otg_control_stop_control
 * Controllerを停止する。
 */

static inline int
usb_otg_control_stop_control(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->stop_control(otg_control);
}

/*
 * 関数：usb_otg_control_start_gadget
 * ControllerをGADGETモードにする。
 */

static inline int
usb_otg_control_start_gadget(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->start_gadget(otg_control);
}

/*
 * 関数：usb_otg_control_stop_gadget
 * ControllerをIDLEモードにする。
 */

static inline int
usb_otg_control_stop_gadget(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->stop_gadget(otg_control);
}

/*
 * 関数：usb_otg_control_enable_rchost
 * ControllerにRCHOSTモードになることを許可する。
 */

static inline int
usb_otg_control_enable_rchost(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->enable_rchost(otg_control);
}

/*
 * 関数：usb_otg_control_disable_rchost
 * ControllerにRCHOSTモードになることを不許可とする。
 */

static inline int
usb_otg_control_disable_rchost(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->disable_rchost(otg_control);
}

/*
 * 関数：usb_otg_control_stop_rchost
 * ControllerをIDLEモードにする。
 */

static inline int
usb_otg_control_stop_rchost(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->stop_rchost(otg_control);
}

/*
 * 関数：usb_otg_control_start_host
 * ControllerをHOSTモードにする。
 */

static inline int
usb_otg_control_start_host(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->start_host(otg_control);
}

/*
 * 関数：usb_otg_control_stop_host
 * ControllerをIDLEモードにする。
 */

static inline int usb_otg_control_stop_host(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->stop_host(otg_control);
}

/*
 * 関数：usb_otg_control_start_rcgadget
 * ControllerをRCGADGETモードにする。
 */

static inline int
usb_otg_control_start_rcgadget(struct usb_otg_control *otg_control,
			       unsigned int port)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->start_rcgadget(otg_control, port);
}

/*
 * 関数：usb_otg_control_stop_rcgadget
 * ControllerをIDLEモードにする。
 */

static inline int
usb_otg_control_stop_rcgadget(struct usb_otg_control *otg_control,
			      unsigned int port)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->stop_rcgadget(otg_control, port);
}

/*
 * 関数：usb_otg_control_get_mode
 * OTGモードを取得する。
 */

static inline int usb_otg_control_get_mode(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->get_mode(otg_control);
}

#define USB_OTG_CONTROL_STOP		1	/* STOPモード */
#define USB_OTG_CONTROL_IDLE		2	/* IDLEモード */
#define USB_OTG_CONTROL_GADGET		3	/* GADGETモード */
#define USB_OTG_CONTROL_RCHOST		4	/* RCHOSTモード */
#define USB_OTG_CONTROL_HOST		5	/* HOSTモード */
#define USB_OTG_CONTROL_RCGADGET	6	/* RCGADGETモード */

/*
 * 関数：usb_otg_control_request_session
 * ControllerにSRPパルシングを要求する。
 */

static inline int
usb_otg_control_request_session(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->request_session(otg_control);
}

/*
 * 関数：usb_otg_control_set_speed
 * 通信スピードを設定する。
 */

static inline int
usb_otg_control_set_speed(struct usb_otg_control *otg_control,
			  unsigned int speed)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->set_speed(otg_control, speed);
}

#define USB_OTG_HS_DISABLE	1	/* High Speedを許可しない。 */
#define USB_OTG_HS_ENABLE	2	/* High Speedを許可する。 */

/*
 * 関数：usb_otg_control_get_speed
 * 通信スピードを取得する。
 */

static inline enum usb_otg_control_speed
usb_otg_control_get_speed(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->get_speed(otg_control);
}

/*
 * 関数：usb_otg_control_set_test_mode
 * テストモードを指定する。
 */

static inline int
usb_otg_control_set_test_mode(struct usb_otg_control *otg_control,
			      enum usb_otg_control_test_mode test_mode)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->set_test_mode(otg_control, test_mode);
}

/*
 * 関数：usb_otg_control_get_test_mode
 * テストモードを取得する。
 */

static inline enum usb_otg_control_test_mode
usb_otg_control_get_test_mode(struct usb_otg_control *otg_control)
{
	if (!otg_control) {
		return -EINVAL;
	}
	return otg_control->ops->get_test_mode(otg_control);
}

#endif				/* _USB_OTG_CONTROL_H_ */
