| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- /*
- * Mediatek XHCI driver for SSUSB.
- *
- * Copyright (C) 2015 Mediatek Inc.
- *
- * Author: Arvin Wang <arvin.wang@mediatek.com>,
- * Macpaul Lin <macpaul.lin@mediatek.com>
- *
- * 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.
- */
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/platform_device.h>
- #include <linux/io.h>
- #include <xhci-mtk.h>
- static struct sch_ep **ss_out_eps[MAX_EP_NUM];
- static struct sch_ep **ss_in_eps[MAX_EP_NUM];
- static struct sch_ep **hs_eps[MAX_EP_NUM]; /* including tt isoc */
- static struct sch_ep **tt_intr_eps[MAX_EP_NUM];
- int mtk_xhci_scheduler_init(void)
- {
- int i;
- for (i = 0; i < MAX_EP_NUM; i++)
- ss_out_eps[i] = NULL;
- for (i = 0; i < MAX_EP_NUM; i++)
- ss_in_eps[i] = NULL;
- for (i = 0; i < MAX_EP_NUM; i++)
- hs_eps[i] = NULL;
- for (i = 0; i < MAX_EP_NUM; i++)
- tt_intr_eps[i] = NULL;
- return 0;
- }
- int add_sch_ep(int dev_speed, int is_in, int isTT, int ep_type, int maxp,
- int interval, int burst, int mult, int offset, int repeat,
- int pkts, int cs_count, int burst_mode, int bw_cost,
- mtk_u32 *ep, struct sch_ep *tmp_ep)
- {
- struct sch_ep **ep_array;
- int i;
- if (is_in && dev_speed == USB_SPEED_SUPER)
- ep_array = (struct sch_ep **)ss_in_eps;
- else if (dev_speed == USB_SPEED_SUPER)
- ep_array = (struct sch_ep **)ss_out_eps;
- else if (dev_speed == USB_SPEED_HIGH || (isTT && ep_type == USB_EP_ISOC))
- ep_array = (struct sch_ep **)hs_eps;
- else
- ep_array = (struct sch_ep **)tt_intr_eps;
- for (i = 0; i < MAX_EP_NUM; i++) {
- if (ep_array[i] == NULL) {
- tmp_ep->dev_speed = dev_speed;
- tmp_ep->isTT = isTT;
- tmp_ep->is_in = is_in;
- tmp_ep->ep_type = ep_type;
- tmp_ep->maxp = maxp;
- tmp_ep->interval = interval;
- tmp_ep->burst = burst;
- tmp_ep->mult = mult;
- tmp_ep->offset = offset;
- tmp_ep->repeat = repeat;
- tmp_ep->pkts = pkts;
- tmp_ep->cs_count = cs_count;
- tmp_ep->burst_mode = burst_mode;
- tmp_ep->bw_cost = bw_cost;
- tmp_ep->ep = ep;
- ep_array[i] = tmp_ep;
- return SCH_SUCCESS;
- }
- }
- return SCH_FAIL;
- }
- int count_ss_bw(int is_in, int ep_type, int maxp, int interval, int burst,
- int mult, int offset, int repeat, int td_size)
- {
- int i, j, k;
- int bw_required[3];
- int final_bw_required;
- int bw_required_per_repeat;
- int tmp_bw_required;
- struct sch_ep *cur_sch_ep;
- struct sch_ep **ep_array;
- int cur_offset;
- int cur_ep_offset;
- int tmp_offset;
- int tmp_interval;
- int ep_offset;
- int ep_interval;
- int ep_repeat;
- int ep_mult;
- if (is_in)
- ep_array = (struct sch_ep **)ss_in_eps;
- else
- ep_array = (struct sch_ep **)ss_out_eps;
- bw_required[0] = 0;
- bw_required[1] = 0;
- bw_required[2] = 0;
- if (repeat == 0) {
- final_bw_required = 0;
- for (i = 0; i < MAX_EP_NUM; i++) {
- cur_sch_ep = ep_array[i];
- if (cur_sch_ep == NULL)
- continue;
- ep_interval = cur_sch_ep->interval;
- ep_offset = cur_sch_ep->offset;
- if (cur_sch_ep->repeat == 0) {
- if (ep_interval >= interval) {
- tmp_offset = ep_offset + ep_interval - offset;
- tmp_interval = interval;
- } else {
- tmp_offset = offset + interval - ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0)
- final_bw_required += cur_sch_ep->bw_cost;
- } else {
- ep_repeat = cur_sch_ep->repeat;
- ep_mult = cur_sch_ep->mult;
- for (k = 0; k <= ep_mult; k++) {
- cur_ep_offset = ep_offset + (k * ep_mult);
- if (ep_interval >= interval) {
- tmp_offset = cur_ep_offset + ep_interval - offset;
- tmp_interval = interval;
- } else {
- tmp_offset = offset + interval - cur_ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0) {
- final_bw_required += cur_sch_ep->bw_cost;
- break;
- }
- }
- }
- }
- final_bw_required += td_size;
- } else {
- bw_required_per_repeat = maxp * (burst + 1);
- for (j = 0; j <= mult; j++) {
- tmp_bw_required = 0;
- cur_offset = offset + (j * repeat);
- for (i = 0; i < MAX_EP_NUM; i++) {
- cur_sch_ep = ep_array[i];
- if (cur_sch_ep == NULL)
- continue;
- ep_interval = cur_sch_ep->interval;
- ep_offset = cur_sch_ep->offset;
- if (cur_sch_ep->repeat == 0) {
- if (ep_interval >= interval) {
- tmp_offset = ep_offset + ep_interval - cur_offset;
- tmp_interval = interval;
- } else {
- tmp_offset = cur_offset + interval - ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0)
- tmp_bw_required += cur_sch_ep->bw_cost;
- } else {
- ep_repeat = cur_sch_ep->repeat;
- ep_mult = cur_sch_ep->mult;
- for (k = 0; k <= ep_mult; k++) {
- cur_ep_offset = ep_offset + (k * ep_repeat);
- if (ep_interval >= interval) {
- tmp_offset = cur_ep_offset + ep_interval - cur_offset;
- tmp_interval = interval;
- } else {
- tmp_offset = cur_offset + interval - cur_ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0) {
- tmp_bw_required += cur_sch_ep->bw_cost;
- break;
- }
- }
- }
- }
- bw_required[j] = tmp_bw_required;
- }
- final_bw_required = SS_BW_BOUND;
- for (j = 0; j <= mult; j++) {
- if (bw_required[j] < final_bw_required)
- final_bw_required = bw_required[j];
- }
- final_bw_required += bw_required_per_repeat;
- }
- return final_bw_required;
- }
- int count_hs_bw(int ep_type, int maxp, int interval, int offset, int td_size)
- {
- int i;
- int bw_required;
- struct sch_ep *cur_sch_ep;
- int tmp_offset;
- int tmp_interval;
- int ep_offset;
- int ep_interval;
- int cur_tt_isoc_interval; /* for isoc tt check */
- bw_required = 0;
- for (i = 0; i < MAX_EP_NUM; i++) {
- cur_sch_ep = (struct sch_ep *)hs_eps[i];
- if (cur_sch_ep == NULL)
- continue;
- ep_offset = cur_sch_ep->offset;
- ep_interval = cur_sch_ep->interval;
- if (cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC) {
- cur_tt_isoc_interval = ep_interval << 3;
- if (ep_interval >= interval) {
- tmp_offset = ep_offset + cur_tt_isoc_interval - offset;
- tmp_interval = interval;
- } else {
- tmp_offset = offset + interval - ep_offset;
- tmp_interval = cur_tt_isoc_interval;
- }
- if (cur_sch_ep->is_in) {
- if ((tmp_offset % tmp_interval >= 2)
- && (tmp_offset % tmp_interval <= cur_sch_ep->cs_count)) {
- bw_required += 188;
- }
- } else {
- if (tmp_offset % tmp_interval <= cur_sch_ep->cs_count)
- bw_required += 188;
- }
- } else {
- if (ep_interval >= interval) {
- tmp_offset = ep_offset + ep_interval - offset;
- tmp_interval = interval;
- } else {
- tmp_offset = offset + interval - ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0)
- bw_required += cur_sch_ep->bw_cost;
- }
- }
- bw_required += td_size;
- return bw_required;
- }
- int count_tt_isoc_bw(int is_in, int maxp, int interval, int offset, int td_size)
- {
- char is_cs;
- int s_frame, s_mframe, cur_mframe;
- int bw_required, max_bw;
- int ss_cs_count;
- int cs_mframe;
- int i, j;
- struct sch_ep *cur_sch_ep;
- int ep_offset;
- int ep_interval;
- int tt_isoc_interval; /* for isoc tt check */
- int cur_tt_isoc_interval; /* for isoc tt check */
- int tmp_offset;
- int tmp_interval;
- is_cs = 0;
- tt_isoc_interval = interval << 3; /* frame to mframe */
- if (is_in)
- is_cs = 1;
- s_frame = offset / 8;
- s_mframe = offset % 8;
- ss_cs_count = (maxp + (188 - 1)) / 188;
- if (is_cs) {
- cs_mframe = offset % 8 + 2 + ss_cs_count;
- if (cs_mframe <= 6)
- ss_cs_count += 2;
- else if (cs_mframe == 7)
- ss_cs_count++;
- else if (cs_mframe > 8)
- return -1;
- }
- max_bw = 0;
- if (is_in)
- i = 2;
- for (cur_mframe = offset + i; i < ss_cs_count; cur_mframe++, i++) {
- bw_required = 0;
- for (j = 0; j < MAX_EP_NUM; j++) {
- cur_sch_ep = (struct sch_ep *)hs_eps[j];
- if (cur_sch_ep == NULL)
- continue;
- ep_offset = cur_sch_ep->offset;
- ep_interval = cur_sch_ep->interval;
- if (cur_sch_ep->isTT && cur_sch_ep->ep_type == USB_EP_ISOC) {
- /* isoc tt */
- /* check if mframe offset overlap */
- /* if overlap, add 188 to the bw */
- cur_tt_isoc_interval = ep_interval << 3;
- if (cur_tt_isoc_interval >= tt_isoc_interval) {
- tmp_offset =
- (ep_offset + cur_tt_isoc_interval) - cur_mframe;
- tmp_interval = tt_isoc_interval;
- } else {
- tmp_offset = (cur_mframe + tt_isoc_interval) - ep_offset;
- tmp_interval = cur_tt_isoc_interval;
- }
- if (cur_sch_ep->is_in) {
- if ((tmp_offset % tmp_interval >= 2)
- && (tmp_offset % tmp_interval <= cur_sch_ep->cs_count)) {
- bw_required += 188;
- }
- } else {
- if (tmp_offset % tmp_interval <= cur_sch_ep->cs_count)
- bw_required += 188;
- }
- } else if (cur_sch_ep->ep_type == USB_EP_INT
- || cur_sch_ep->ep_type == USB_EP_ISOC) {
- /* check if mframe */
- if (ep_interval >= tt_isoc_interval) {
- tmp_offset = (ep_offset + ep_interval) - cur_mframe;
- tmp_interval = tt_isoc_interval;
- } else {
- tmp_offset = (cur_mframe + tt_isoc_interval) - ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0)
- bw_required += cur_sch_ep->bw_cost;
- }
- }
- bw_required += 188;
- if (bw_required > max_bw)
- max_bw = bw_required;
- }
- return max_bw;
- }
- int count_tt_intr_bw(int interval, int frame_offset)
- {
- /* check all eps in tt_intr_eps */
- int ret;
- int i;
- int ep_offset;
- int ep_interval;
- int tmp_offset;
- int tmp_interval;
- struct sch_ep *cur_sch_ep;
- ret = SCH_SUCCESS;
- for (i = 0; i < MAX_EP_NUM; i++) {
- cur_sch_ep = (struct sch_ep *)tt_intr_eps[i];
- if (cur_sch_ep == NULL)
- continue;
- ep_offset = cur_sch_ep->offset;
- ep_interval = cur_sch_ep->interval;
- if (ep_interval >= interval) {
- tmp_offset = ep_offset + ep_interval - frame_offset;
- tmp_interval = interval;
- } else {
- tmp_offset = frame_offset + interval - ep_offset;
- tmp_interval = ep_interval;
- }
- if (tmp_offset % tmp_interval == 0)
- return SCH_FAIL;
- }
- return SCH_SUCCESS;
- }
- struct sch_ep *mtk_xhci_scheduler_remove_ep(int dev_speed, int is_in, int isTT,
- int ep_type, mtk_u32 *ep)
- {
- int i;
- struct sch_ep **ep_array;
- struct sch_ep *cur_ep;
- if (is_in && dev_speed == USB_SPEED_SUPER)
- ep_array = (struct sch_ep **)ss_in_eps;
- else if (dev_speed == USB_SPEED_SUPER)
- ep_array = (struct sch_ep **)ss_out_eps;
- else if (dev_speed == USB_SPEED_HIGH || (isTT && ep_type == USB_EP_ISOC))
- ep_array = (struct sch_ep **)hs_eps;
- else
- ep_array = (struct sch_ep **)tt_intr_eps;
- for (i = 0; i < MAX_EP_NUM; i++) {
- cur_ep = (struct sch_ep *)ep_array[i];
- if (cur_ep != NULL && cur_ep->ep == ep) {
- ep_array[i] = NULL;
- return cur_ep;
- }
- }
- return NULL;
- }
- int mtk_xhci_scheduler_add_ep(int dev_speed, int is_in, int isTT, int ep_type,
- int maxp, int interval, int burst, int mult,
- mtk_u32 *ep, mtk_u32 *ep_ctx,
- struct sch_ep *sch_ep)
- {
- mtk_u32 bPkts = 0;
- mtk_u32 bCsCount = 0;
- mtk_u32 bBm = 1;
- mtk_u32 bOffset = 0;
- mtk_u32 bRepeat = 0;
- int ret;
- struct mtk_xhci_ep_ctx *temp_ep_ctx;
- int td_size;
- int mframe_idx, frame_idx;
- int bw_cost;
- int cur_bw, best_bw, best_bw_idx, repeat, max_repeat, best_bw_repeat;
- int cur_offset, cs_mframe;
- int break_out;
- int frame_interval;
- best_bw_repeat = 0;
- pr_debug("add_ep parameters, dev_speed : %d\n"
- "is_in : %d\n"
- "isTT : %d\n"
- "ep_type : %d\n"
- "maxp : %d\n"
- "interval: %d\n"
- "burst : %d\n"
- "mult : %d\n"
- "ep : 0x%p\n"
- "ep_ctx : 0x%p\n"
- "sch_ep : 0x%p\n",
- dev_speed, is_in, isTT, ep_type,
- maxp, interval, burst, mult,
- ep, ep_ctx, sch_ep);
- if (isTT && ep_type == USB_EP_INT
- && ((dev_speed == USB_SPEED_LOW) || (dev_speed == USB_SPEED_FULL))) {
- frame_interval = interval >> 3;
- for (frame_idx = 0; frame_idx < frame_interval; frame_idx++) {
- pr_debug("check tt_intr_bw interval %d, frame_idx %d\n",
- frame_interval, frame_idx);
- if (count_tt_intr_bw(frame_interval, frame_idx) == SCH_SUCCESS) {
- pr_debug("check OK............\n");
- bOffset = frame_idx << 3;
- bPkts = 1;
- bCsCount = 3;
- bw_cost = maxp;
- bRepeat = 0;
- if (add_sch_ep
- (dev_speed, is_in, isTT, ep_type, maxp, frame_interval, burst,
- mult, bOffset, bRepeat, bPkts, bCsCount, bBm, maxp, ep,
- sch_ep) == SCH_FAIL) {
- return SCH_FAIL;
- }
- ret = SCH_SUCCESS;
- break;
- }
- }
- } else if (isTT && ep_type == USB_EP_ISOC) {
- best_bw = HS_BW_BOUND;
- best_bw_idx = -1;
- cur_bw = 0;
- td_size = maxp;
- break_out = 0;
- frame_interval = interval >> 3;
- for (frame_idx = 0; frame_idx < frame_interval && !break_out; frame_idx++) {
- for (mframe_idx = 0; mframe_idx < 8; mframe_idx++) {
- cur_offset = (frame_idx * 8) + mframe_idx;
- cur_bw =
- count_tt_isoc_bw(is_in, maxp, frame_interval, cur_offset,
- td_size);
- if (cur_bw > 0 && cur_bw < best_bw) {
- best_bw_idx = cur_offset;
- best_bw = cur_bw;
- if (cur_bw == td_size || cur_bw < (HS_BW_BOUND >> 1)) {
- break_out = 1;
- break;
- }
- }
- }
- }
- if (best_bw_idx == -1)
- return SCH_FAIL;
- bOffset = best_bw_idx;
- bPkts = 1;
- bCsCount = maxp + (188 - 1) / 188;
- if (is_in) {
- cs_mframe = bOffset % 8 + 2 + bCsCount;
- if (cs_mframe <= 6)
- bCsCount += 2;
- else if (cs_mframe == 7)
- bCsCount++;
- }
- bw_cost = 188;
- bRepeat = 0;
- if (add_sch_ep
- (dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult, bOffset,
- bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL) {
- return SCH_FAIL;
- }
- ret = SCH_SUCCESS;
- } else if ((dev_speed == USB_SPEED_FULL || dev_speed == USB_SPEED_LOW)
- && ep_type == USB_EP_INT) {
- bPkts = 1;
- ret = SCH_SUCCESS;
- } else if (dev_speed == USB_SPEED_FULL && ep_type == USB_EP_ISOC) {
- bPkts = 1;
- ret = SCH_SUCCESS;
- } else if (dev_speed == USB_SPEED_HIGH && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)) {
- best_bw = HS_BW_BOUND;
- best_bw_idx = -1;
- cur_bw = 0;
- td_size = maxp * (burst + 1);
- for (cur_offset = 0; cur_offset < interval; cur_offset++) {
- cur_bw = count_hs_bw(ep_type, maxp, interval, cur_offset, td_size);
- if (cur_bw > 0 && cur_bw < best_bw) {
- best_bw_idx = cur_offset;
- best_bw = cur_bw;
- if (cur_bw == td_size || cur_bw < (HS_BW_BOUND >> 1))
- break;
- }
- }
- if (best_bw_idx == -1)
- return SCH_FAIL;
- bOffset = best_bw_idx;
- bPkts = burst + 1;
- bCsCount = 0;
- bw_cost = td_size;
- bRepeat = 0;
- if (add_sch_ep
- (dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult, bOffset,
- bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL) {
- return SCH_FAIL;
- }
- ret = SCH_SUCCESS;
- } else if (dev_speed == USB_SPEED_SUPER
- && (ep_type == USB_EP_INT || ep_type == USB_EP_ISOC)) {
- best_bw = SS_BW_BOUND;
- best_bw_idx = -1;
- cur_bw = 0;
- td_size = maxp * (mult + 1) * (burst + 1);
- if (mult == 0)
- max_repeat = 0;
- else
- max_repeat = (interval - 1) / (mult + 1);
- break_out = 0;
- for (frame_idx = 0; (frame_idx < interval) && !break_out; frame_idx++) {
- for (repeat = max_repeat; repeat >= 0; repeat--) {
- cur_bw =
- count_ss_bw(is_in, ep_type, maxp, interval, burst, mult,
- frame_idx, repeat, td_size);
- pr_debug
- ("count_ss_bw, frame_idx %d, repeat %d, td_size %d, result bw %d\n",
- frame_idx, repeat, td_size, cur_bw);
- if (cur_bw > 0 && cur_bw < best_bw) {
- best_bw_idx = frame_idx;
- best_bw_repeat = repeat;
- best_bw = cur_bw;
- if (cur_bw <= td_size || cur_bw < (HS_BW_BOUND >> 1)) {
- break_out = 1;
- break;
- }
- }
- }
- }
- pr_debug("final best idx %d, best repeat %d\n", best_bw_idx, best_bw_repeat);
- if (best_bw_idx == -1)
- return SCH_FAIL;
- bOffset = best_bw_idx;
- bCsCount = 0;
- bRepeat = best_bw_repeat;
- if (bRepeat == 0) {
- bw_cost = (burst + 1) * (mult + 1) * maxp;
- bPkts = (burst + 1) * (mult + 1);
- } else {
- bw_cost = (burst + 1) * maxp;
- bPkts = (burst + 1);
- }
- if (add_sch_ep
- (dev_speed, is_in, isTT, ep_type, maxp, interval, burst, mult, bOffset,
- bRepeat, bPkts, bCsCount, bBm, bw_cost, ep, sch_ep) == SCH_FAIL) {
- return SCH_FAIL;
- }
- ret = SCH_SUCCESS;
- } else {
- bPkts = 1;
- ret = SCH_SUCCESS;
- }
- if (ret == SCH_SUCCESS) {
- temp_ep_ctx = (struct mtk_xhci_ep_ctx *)ep_ctx;
- temp_ep_ctx->reserved[0] |= (BPKTS(bPkts) | BCSCOUNT(bCsCount) | BBM(bBm));
- temp_ep_ctx->reserved[1] |= (BOFFSET(bOffset) | BREPEAT(bRepeat));
- pr_debug("[DBG] BPKTS: %x, BCSCOUNT: %x, BBM: %x\n", (unsigned int)bPkts,
- (unsigned int)bCsCount, (unsigned int)bBm);
- pr_debug("[DBG] BOFFSET: %x, BREPEAT: %x\n", (unsigned int)bOffset,
- (unsigned int)bRepeat);
- return SCH_SUCCESS;
- } else {
- return SCH_FAIL;
- }
- }
- void mtk_xhci_vbus_on(struct platform_device *pdev)
- {
- struct pinctrl *pinctrl;
- struct pinctrl_state *pinctrl_drvvbus_high;
- pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "Cannot find usb pinctrl!\n");
- return;
- }
- pinctrl_drvvbus_high = pinctrl_lookup_state(pinctrl, "drvvbus_high");
- if (IS_ERR(pinctrl_drvvbus_high)) {
- dev_err(&pdev->dev, "Cannot find usb pinctrl drvvbus_high\n");
- return;
- }
- pinctrl_select_state(pinctrl, pinctrl_drvvbus_high);
- }
- void mtk_xhci_vbus_off(struct platform_device *pdev)
- {
- struct pinctrl *pinctrl;
- struct pinctrl_state *pinctrl_drvvbus_low;
- pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "Cannot find usb pinctrl!\n");
- return;
- }
- pinctrl_drvvbus_low = pinctrl_lookup_state(pinctrl, "drvvbus_low");
- if (IS_ERR(pinctrl_drvvbus_low)) {
- dev_err(&pdev->dev, "Cannot find usb pinctrl drvvbus_low\n");
- return;
- }
- pinctrl_select_state(pinctrl, pinctrl_drvvbus_low);
- }
- MODULE_DESCRIPTION(DRIVER_DESC);
- MODULE_AUTHOR("Arvin Wang <arvin.wang@mediatek.com>");
- MODULE_AUTHOR("Macpaul Lin <macpaul.lin@mediatek.com>");
- MODULE_LICENSE("GPL");
|