2020-09-23 05:31:06 -06:00
|
|
|
/*
|
|
|
|
* reMarkable OTG Control
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/
|
|
|
|
*
|
|
|
|
* Author: Steinar Bakkemo <steinar.bakkemo@remarkable.com>
|
|
|
|
*
|
|
|
|
* 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 version 2.
|
|
|
|
*
|
|
|
|
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
|
|
* kind, whether express or implied; without even the implied warranty
|
|
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
2020-10-08 10:30:57 -06:00
|
|
|
#include "otgcontrol_dr_mode.h"
|
|
|
|
|
2020-10-08 11:25:40 -06:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
|
|
static const unsigned int usb_extcon_cable[] = {
|
2020-10-08 11:46:24 -06:00
|
|
|
EXTCON_USB_HOST,
|
|
|
|
EXTCON_NONE,
|
2020-10-08 11:25:40 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
int otgcontrol_init_extcon(struct rm_otgcontrol_data *otgc_data)
|
|
|
|
{
|
2020-10-08 11:46:24 -06:00
|
|
|
int ret;
|
2020-10-08 11:25:40 -06:00
|
|
|
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_dbg(otgc_data->dev,
|
|
|
|
"%s: Allocating extcon device\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
otgc_data->extcon_dev = devm_extcon_dev_allocate(otgc_data->dev,
|
|
|
|
usb_extcon_cable);
|
2020-10-08 11:46:24 -06:00
|
|
|
if (IS_ERR(otgc_data->extcon_dev)) {
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_err(otgc_data->dev,
|
|
|
|
"%s: failed to allocate extcon device\n",
|
|
|
|
__func__);
|
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2020-10-08 11:25:40 -06:00
|
|
|
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_dbg(otgc_data->dev,
|
|
|
|
"%s: Registering extcon device\n",
|
|
|
|
__func__);
|
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
ret = devm_extcon_dev_register(otgc_data->dev, otgc_data->extcon_dev);
|
|
|
|
if (ret < 0) {
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_err(otgc_data->dev,
|
|
|
|
"%s: Failed to register extcon device\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
dev_dbg(otgc_data->dev,
|
|
|
|
"%s: De-allocating extcon device\n",
|
|
|
|
__func__);
|
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
kfree(otgc_data->extcon_dev);
|
|
|
|
otgc_data->extcon_dev = NULL;
|
|
|
|
return ret;
|
|
|
|
}
|
2020-10-08 11:25:40 -06:00
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
return 0;
|
2020-10-08 11:25:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int otgcontrol_set_dr_mode(struct rm_otgcontrol_data *otgc_data, int mode)
|
2020-10-08 10:30:57 -06:00
|
|
|
{
|
2019-08-20 13:25:17 -06:00
|
|
|
int ret;
|
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case OTG1_DR_MODE__DEVICE:
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_dbg(otgc_data->dev,
|
|
|
|
"%s: Switching OTG1 DR mode -> DEVICE\n",
|
|
|
|
__func__);
|
|
|
|
|
2019-08-20 13:25:17 -06:00
|
|
|
ret = extcon_set_state_sync(otgc_data->extcon_dev,
|
|
|
|
EXTCON_USB_HOST,
|
|
|
|
false);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(otgc_data->dev,
|
|
|
|
"%s: Failed to set OTG1 DR mode\n",
|
|
|
|
__func__);
|
2020-10-08 12:03:39 -06:00
|
|
|
|
2019-08-20 13:25:17 -06:00
|
|
|
return ret;
|
|
|
|
}
|
2020-10-08 11:46:24 -06:00
|
|
|
break;
|
2020-10-08 10:30:57 -06:00
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
case OTG1_DR_MODE__HOST:
|
2020-10-08 12:03:39 -06:00
|
|
|
dev_dbg(otgc_data->dev,
|
|
|
|
"%s: Switching OTG1 DR mode -> HOST\n",
|
|
|
|
__func__);
|
|
|
|
|
2019-08-20 13:25:17 -06:00
|
|
|
otgc_data->otg1_dr_mode = mode;
|
|
|
|
ret = extcon_set_state_sync(otgc_data->extcon_dev,
|
|
|
|
EXTCON_USB_HOST,
|
|
|
|
true);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(otgc_data->dev,
|
|
|
|
"%s: Failed to set OTG1 DR mode\n",
|
|
|
|
__func__);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2020-10-08 11:46:24 -06:00
|
|
|
break;
|
2020-10-08 10:30:57 -06:00
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
default:
|
2019-08-20 13:25:17 -06:00
|
|
|
dev_err(otgc_data->dev,
|
2020-10-08 12:03:39 -06:00
|
|
|
"%s: unable to switch OTG1 DR mode (unknown mode %d)\n",
|
|
|
|
__func__,
|
|
|
|
mode);
|
|
|
|
|
2020-10-08 11:46:24 -06:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2019-08-20 13:25:17 -06:00
|
|
|
|
|
|
|
otgc_data->otg1_dr_mode = mode;
|
|
|
|
return ret;
|
2020-10-08 10:30:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int otgcontrol_get_dr_mode(struct rm_otgcontrol_data *otgc_data)
|
|
|
|
{
|
2020-10-08 11:46:24 -06:00
|
|
|
/* Just return the last stored value */
|
|
|
|
return otgc_data->otg1_dr_mode;
|
2020-10-08 10:30:57 -06:00
|
|
|
}
|