/* * reMarkable OTG Control * * Copyright (C) 2019 reMarkable AS - http://www.remarkable.com/ * * Author: Steinar Bakkemo * * 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 #include #include #include #include #include #include #include #include #include #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(get_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(get_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; } }