1
0
Fork 0
alistair23-linux/drivers/misc/rm-otgcontrol/otgcontrol_onewire.c

514 lines
12 KiB
C

/*
* 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.
*/
#include "otgcontrol_onewire.h"
#include "otgcontrol_fsm.h"
#include <linux/export.h>
#include <linux/errno.h>
#include <linux/pinctrl/consumer.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
#define ONE_WIRE_GPIO_DEBOUNCE_MS 500 /* ms */
int otgcontrol_init_one_wire_mux_state(struct rm_otgcontrol_data *otgc_data)
{
int ret;
dev_dbg(otgc_data->dev,
"%s: Initiating one-wire pinctrl states\n",
__func__);
otgc_data->one_wire_pinctrl = devm_pinctrl_get(otgc_data->dev);
if (IS_ERR(otgc_data->one_wire_pinctrl)) {
dev_err(otgc_data->dev,
"%s: Failed to get pinctrl\n",
__func__);
return PTR_ERR(otgc_data->one_wire_pinctrl);
}
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__GPIO] =
pinctrl_lookup_state(otgc_data->one_wire_pinctrl,
"default");
if (IS_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__GPIO])) {
dev_err(otgc_data->dev,
"%s: Failed to configure one-wire-gpio state\n",
__func__);
devm_pinctrl_put(otgc_data->one_wire_pinctrl);
return PTR_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__GPIO]);
}
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_TX] =
pinctrl_lookup_state(otgc_data->one_wire_pinctrl,
"one_wire_uart_tx");
if (IS_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_TX])) {
dev_err(otgc_data->dev,
"%s: Failed to configure one-wire-uart-tx state\n",
__func__);
devm_pinctrl_put(otgc_data->one_wire_pinctrl);
return PTR_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_TX]);
}
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_RX] =
pinctrl_lookup_state(otgc_data->one_wire_pinctrl,
"one_wire_uart_rx");
if (IS_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_RX])) {
dev_err(otgc_data->dev,
"%s: Failed to configure one-wire-uart-rx\n",
__func__);
devm_pinctrl_put(otgc_data->one_wire_pinctrl);
return PTR_ERR(otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_RX]);
}
dev_dbg(otgc_data->dev,
"%s: Setting default state (GPIO)\n",
__func__);
ret = pinctrl_select_state(
otgc_data->one_wire_pinctrl,
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__GPIO]);
if (ret < 0) {
dev_err(otgc_data->dev,
"%s: Failed to set default state (GPIO)\n",
__func__);
devm_pinctrl_put(otgc_data->one_wire_pinctrl);
}
otgc_data->otg1_pinctrlstate = OTG1_ONEWIRE_STATE__GPIO;
return 0;
}
int otgcontrol_switch_one_wire_mux_state(struct rm_otgcontrol_data *otgc_data,
int state)
{
int ret;
switch(state)
{
case OTG1_ONEWIRE_STATE__GPIO:
dev_dbg(otgc_data->dev,
"%s: Switching onewire state -> GPIO\n",
__func__);
ret = pinctrl_select_state(
otgc_data->one_wire_pinctrl,
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__GPIO]);
if (ret < 0) {
dev_err(otgc_data->dev,
"%s: Failed to set pinctrl state\n",
__func__);
return ret;
}
break;
case OTG1_ONEWIRE_STATE__UART_RX:
dev_dbg(otgc_data->dev,
"%s: Switching onewire state -> UART RX\n",
__func__);
ret = pinctrl_select_state(
otgc_data->one_wire_pinctrl,
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_RX]);
if (ret < 0) {
dev_err(otgc_data->dev,
"%s: Failed to set pinctrl state\n",
__func__);
return ret;
}
break;
case OTG1_ONEWIRE_STATE__UART_TX:
dev_dbg(otgc_data->dev,
"%s: switching onewire state -> UART TX\n",
__func__);
ret = pinctrl_select_state(
otgc_data->one_wire_pinctrl,
otgc_data->one_wire_pinctrl_states[OTG1_ONEWIRE_STATE__UART_TX]);
if (ret < 0) {
dev_err(otgc_data->dev,
"%s: Failed to set pinctrl state\n",
__func__);
return ret;
}
break;
default:
dev_err(otgc_data->dev,
"%s: unable to switch onewire state (unknown state %d)\n",
__func__, state);
return -EINVAL;
}
otgc_data->otg1_pinctrlstate = state;
return 0;
}
int otgcontrol_get_current_gpio_state(struct rm_otgcontrol_data *otgc_data)
{
return SYNC_GET_FLAG(gpiod_get_raw_value(otgc_data->pdata->one_wire_gpio),
&otgc_data->lock);
}
const char *otgcontrol_gpio_state_name(int state)
{
switch(state)
{
case OTG1_ONEWIRE_GPIO_STATE__DEVICE_CONNECTED:
return "DEVICE CONNECTED";
break;
case OTG1_ONEWIRE_GPIO_STATE__DEVICE_NOT_CONNECTED:
return "DEVICE NOT CONNECTED";
break;
default:
return "UNKNOWN DEVICE CONNECTION STATE EXPECTED 0 or 1)";
}
}
int otgcontrol_init_gpio_irq(struct rm_otgcontrol_data *otgc_data)
{
int ret;
dev_dbg(otgc_data->dev,
"%s: Setting local gpio debounce jiffies\n",
__func__);
otgc_data->one_wire_gpio_debounce_jiffies =
msecs_to_jiffies(ONE_WIRE_GPIO_DEBOUNCE_MS);
dev_dbg(otgc_data->dev,
"%s: Initiating irq worker\n",
__func__);
INIT_DELAYED_WORK(&otgc_data->one_wire_gpio_irq_work_queue,
otgcontrol_gpio_irq_work);
dev_dbg(otgc_data->dev,
"%s: Getting IRQ from given gpio (%d)\n",
__func__,
desc_to_gpio(otgc_data->pdata->one_wire_gpio));
otgc_data->pdata->one_wire_gpio_irq = gpiod_to_irq(otgc_data->pdata->one_wire_gpio);
if (otgc_data->pdata->one_wire_gpio_irq < 0) {
dev_err(otgc_data->dev,
"%s: Failed to get irq for given gpio (%d)\n",
__func__,
desc_to_gpio(otgc_data->pdata->one_wire_gpio));
return otgc_data->pdata->one_wire_gpio_irq;
}
otgc_data->one_wire_gpio_state =
otgcontrol_get_current_gpio_state(otgc_data);
dev_dbg(otgc_data->dev,
"%s: Current GPIO state: %s\n",
__func__,
otgcontrol_gpio_state_name(otgc_data->one_wire_gpio_state));
dev_dbg(otgc_data->dev,
"%s: Clearing is-handling flag\n",
__func__);
otgc_data->one_wire_gpio_irq_is_handling = false;
dev_dbg(otgc_data->dev,
"%s: Requesting threaded irq\n",
__func__);
ret = devm_request_threaded_irq(
otgc_data->dev,
otgc_data->pdata->one_wire_gpio_irq,
NULL,
otgcontrol_gpio_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"one_wire_gpio_irq",
otgc_data);
if (ret < 0) {
dev_err(otgc_data->dev,
"%s: Failed to request handler for IRQ (%d) "
"given for GPIO (%d)\n",
__func__,
otgc_data->pdata->one_wire_gpio_irq,
desc_to_gpio(otgc_data->pdata->one_wire_gpio));
return ret;
}
mutex_lock(&otgc_data->lock);
otgc_data->one_wire_gpio_irq_is_active = true;
mutex_unlock(&otgc_data->lock);
return 0;
}
void otgcontrol_uninit_gpio_irq(struct rm_otgcontrol_data *otgc_data)
{
cancel_delayed_work_sync(&otgc_data->one_wire_gpio_irq_work_queue);
}
void otgcontrol_activate_gpio_irq(struct rm_otgcontrol_data *otgc_data)
{
if (!otgc_data->one_wire_gpio_irq_is_active) {
enable_irq(otgc_data->pdata->one_wire_gpio_irq);
otgc_data->one_wire_gpio_irq_is_active = true;
}
}
void otgcontrol_deactivate_gpio_irq(struct rm_otgcontrol_data *otgc_data)
{
if (otgc_data->one_wire_gpio_irq_is_active) {
disable_irq(otgc_data->pdata->one_wire_gpio_irq);
otgc_data->one_wire_gpio_irq_is_active = false;
}
}
static irqreturn_t otgcontrol_gpio_irq_handler(int irq, void *data)
{
struct rm_otgcontrol_data *otgc_data = (struct rm_otgcontrol_data*)data;
if (SYNC_GET_FLAG(otgc_data->one_wire_gpio_irq_is_handling,
&otgc_data->lock)) {
dev_dbg(otgc_data->dev,
"%s: Is already handling irq, ignoring this\n",
__func__);
return IRQ_HANDLED;
}
else {
dev_dbg(otgc_data->dev,
"%s: Queueing IRQ handling for execution in %d ms\n",
__func__,
ONE_WIRE_GPIO_DEBOUNCE_MS);
SYNC_SET_FLAG(otgc_data->one_wire_gpio_irq_is_handling,
&otgc_data->lock);
queue_delayed_work(system_power_efficient_wq,
&otgc_data->one_wire_gpio_irq_work_queue,
otgc_data->one_wire_gpio_debounce_jiffies);
}
return IRQ_HANDLED;
}
static void otgcontrol_gpio_irq_work(struct work_struct *work)
{
int cur_gpio_state;
struct delayed_work *delayed_work =
container_of(work,
struct delayed_work,
work);
struct rm_otgcontrol_data *otgc_data =
container_of(delayed_work,
struct rm_otgcontrol_data,
one_wire_gpio_irq_work_queue);
dev_dbg(otgc_data->dev,
"%s: Checking current gpio state\n",
__func__);
cur_gpio_state = otgcontrol_get_current_gpio_state(otgc_data);
if (cur_gpio_state != otgc_data->one_wire_gpio_state) {
dev_dbg(otgc_data->dev,
"%s: GPIO state changed -> %s\n",
__func__,
otgcontrol_gpio_state_name(cur_gpio_state));
otgc_data->one_wire_gpio_state = cur_gpio_state;
if (otgc_data->one_wire_gpio_state ==
OTG1_ONEWIRE_GPIO_STATE__DEVICE_CONNECTED) {
SYNC_SET_FLAG(otgc_data->otg1_device_connected,
&otgc_data->lock);
otgcontrol_handleInput(otgc_data,
OTG1_EVENT__DEVICE_CONNECTED,
NULL);
}
else {
SYNC_CLEAR_FLAG(otgc_data->otg1_device_connected,
&otgc_data->lock);
otgcontrol_handleInput(otgc_data,
OTG1_EVENT__DEVICE_DISCONNECTED,
NULL);
}
}
SYNC_CLEAR_FLAG(otgc_data->one_wire_gpio_irq_is_handling,
&otgc_data->lock);
}
int otgcontrol_onewire_write_tty(struct rm_otgcontrol_data *otgc_data,
char *device_name,
char *text_to_send)
{
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
for(i = 0;i < 128;i++)
buf[i] = 0;
dev_dbg(otgc_data->dev, "%s: Trying to open %s\n",
__func__,
device_name);
f = filp_open(device_name, O_RDWR, 0);
if(f == NULL) {
dev_err(otgc_data->dev,
"%s: filp_open error!!.\n",
__func__);
return -1;
}
else {
dev_dbg(otgc_data->dev,
"%s: Getting current segment descriptor\n",
__func__);
fs = get_fs();
dev_dbg(otgc_data->dev,
"%s: Setting segment descriptor\n",
__func__);
set_fs(KERNEL_DS);
dev_dbg(otgc_data->dev,
"%s: Writing '%s' to file\n",
__func__,
text_to_send);
kernel_write(f,
text_to_send,
strlen(text_to_send),
&f->f_pos);
dev_dbg(otgc_data->dev,
"%s: Restoring segment descriptor\n",
__func__);
set_fs(fs);
dev_dbg(otgc_data->dev,
"%s: Closing file\n",
__func__);
filp_close(f,NULL);
return 0;
}
}
int otgcontrol_onewire_read_until_cr(struct rm_otgcontrol_data *otgc_data, char *device_name, char *buf, int maxlen)
{
struct file *f;
mm_segment_t fs;
char newchar;
int pos, state;
f = filp_open(device_name, O_RDONLY, 0);
if(f == NULL) {
dev_err(otgc_data->dev,
"%s: filp_open error!!.\n",
__func__);
return -1;
}
else {
dev_dbg(otgc_data->dev,
"%s: Getting current segment descriptor\n",
__func__);
fs = get_fs();
dev_dbg(otgc_data->dev,
"%s: Setting segment descriptor\n",
__func__);
set_fs(KERNEL_DS);
pos = 0;
state = 0;
dev_dbg(otgc_data->dev,
"%s: Starting read loop\n",
__func__);
do {
kernel_read(f,
&newchar,
1,
&f->f_pos);
dev_dbg(otgc_data->dev,
"%s: <-%c (0x%02x)\n",
__func__,
newchar, newchar);
switch(state)
{
case 0:
if (newchar == ':') {
dev_dbg(otgc_data->dev,
"%s: SOF\n",
__func__);
state = 1;
}
break;
default:
if (newchar != '#') {
buf[pos++] = newchar;
}
}
}while((newchar != '#') && (pos < maxlen));
dev_dbg(otgc_data->dev,
"%s: Done\n",
__func__);
dev_dbg(otgc_data->dev,
"%s: Restoring segment descriptor\n",
__func__);
set_fs(fs);
dev_dbg(otgc_data->dev,
"%s: Closing file\n",
__func__);
filp_close(f, NULL);
dev_dbg(otgc_data->dev,
"%s: Returning %d bytes read\n",
__func__,
pos);
return pos;
}
}