^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for IMS Passenger Control Unit Devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2013 The IMS Company
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/ihex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/usb/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/usb/cdc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define IMS_PCU_KEYMAP_LEN 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct ims_pcu_buttons {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) char name[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned short keymap[IMS_PCU_KEYMAP_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct ims_pcu_gamepad {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) char name[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct ims_pcu_backlight {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct led_classdev cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) char name[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IMS_PCU_PART_NUMBER_LEN 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define IMS_PCU_SERIAL_NUMBER_LEN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define IMS_PCU_DOM_LEN 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define IMS_PCU_FW_VERSION_LEN (9 + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define IMS_PCU_BL_VERSION_LEN (9 + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define IMS_PCU_PCU_B_DEVICE_ID 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define IMS_PCU_BUF_SIZE 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct ims_pcu {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct usb_device *udev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct device *dev; /* control interface's device, used for logging */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned int device_no;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) bool bootloader_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) char part_number[IMS_PCU_PART_NUMBER_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) char serial_number[IMS_PCU_SERIAL_NUMBER_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) char date_of_manufacturing[IMS_PCU_DOM_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) char fw_version[IMS_PCU_FW_VERSION_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) char bl_version[IMS_PCU_BL_VERSION_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int update_firmware_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 device_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u8 ofn_reg_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct usb_interface *ctrl_intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct usb_endpoint_descriptor *ep_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct urb *urb_ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u8 *urb_ctrl_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) dma_addr_t ctrl_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) size_t max_ctrl_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct usb_interface *data_intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct usb_endpoint_descriptor *ep_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct urb *urb_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u8 *urb_in_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) dma_addr_t read_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) size_t max_in_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct usb_endpoint_descriptor *ep_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u8 *urb_out_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) size_t max_out_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u8 read_buf[IMS_PCU_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u8 read_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u8 check_sum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) bool have_stx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) bool have_dle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u8 cmd_buf[IMS_PCU_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u8 ack_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u8 expected_response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u8 cmd_buf_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct completion cmd_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct mutex cmd_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) u32 fw_start_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 fw_end_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct completion async_firmware_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct ims_pcu_buttons buttons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct ims_pcu_gamepad *gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct ims_pcu_backlight backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) bool setup_complete; /* Input and LED devices have been created */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * Buttons Input device support *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const unsigned short ims_pcu_keymap_1[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) [1] = KEY_ATTENDANT_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) [2] = KEY_ATTENDANT_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) [3] = KEY_LIGHTS_TOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) [4] = KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) [5] = KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) [6] = KEY_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static const unsigned short ims_pcu_keymap_2[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) [4] = KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) [5] = KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) [6] = KEY_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static const unsigned short ims_pcu_keymap_3[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) [1] = KEY_HOMEPAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) [2] = KEY_ATTENDANT_TOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) [3] = KEY_LIGHTS_TOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) [4] = KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) [5] = KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) [6] = KEY_DISPLAYTOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) [18] = KEY_PLAYPAUSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static const unsigned short ims_pcu_keymap_4[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) [1] = KEY_ATTENDANT_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) [2] = KEY_ATTENDANT_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) [3] = KEY_LIGHTS_TOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) [4] = KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) [5] = KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) [6] = KEY_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) [18] = KEY_PLAYPAUSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static const unsigned short ims_pcu_keymap_5[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) [1] = KEY_ATTENDANT_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) [2] = KEY_ATTENDANT_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) [3] = KEY_LIGHTS_TOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct ims_pcu_device_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) const unsigned short *keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) size_t keymap_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) bool has_gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #define IMS_PCU_DEVINFO(_n, _gamepad) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) [_n] = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .keymap = ims_pcu_keymap_##_n, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .keymap_len = ARRAY_SIZE(ims_pcu_keymap_##_n), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .has_gamepad = _gamepad, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static const struct ims_pcu_device_info ims_pcu_device_info[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) IMS_PCU_DEVINFO(1, true),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) IMS_PCU_DEVINFO(2, true),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) IMS_PCU_DEVINFO(3, true),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) IMS_PCU_DEVINFO(4, true),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) IMS_PCU_DEVINFO(5, false),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static void ims_pcu_buttons_report(struct ims_pcu *pcu, u32 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct ims_pcu_buttons *buttons = &pcu->buttons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct input_dev *input = buttons->input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) for (i = 0; i < 32; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) unsigned short keycode = buttons->keymap[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (keycode != KEY_RESERVED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) input_report_key(input, keycode, data & (1UL << i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) input_sync(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static int ims_pcu_setup_buttons(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) const unsigned short *keymap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) size_t keymap_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct ims_pcu_buttons *buttons = &pcu->buttons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!input) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) "Not enough memory for input input device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) snprintf(buttons->name, sizeof(buttons->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) "IMS PCU#%d Button Interface", pcu->device_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) usb_make_path(pcu->udev, buttons->phys, sizeof(buttons->phys));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) strlcat(buttons->phys, "/input0", sizeof(buttons->phys));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) memcpy(buttons->keymap, keymap, sizeof(*keymap) * keymap_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) input->name = buttons->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) input->phys = buttons->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) usb_to_input_id(pcu->udev, &input->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) input->dev.parent = &pcu->ctrl_intf->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) input->keycode = buttons->keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) input->keycodemax = ARRAY_SIZE(buttons->keymap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) input->keycodesize = sizeof(buttons->keymap[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) __set_bit(EV_KEY, input->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) for (i = 0; i < IMS_PCU_KEYMAP_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) __set_bit(buttons->keymap[i], input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) __clear_bit(KEY_RESERVED, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) "Failed to register buttons input device: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) buttons->input = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void ims_pcu_destroy_buttons(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct ims_pcu_buttons *buttons = &pcu->buttons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) input_unregister_device(buttons->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Gamepad Input device support *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static void ims_pcu_gamepad_report(struct ims_pcu *pcu, u32 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct ims_pcu_gamepad *gamepad = pcu->gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct input_dev *input = gamepad->input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int x, y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) x = !!(data & (1 << 14)) - !!(data & (1 << 13));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) y = !!(data & (1 << 12)) - !!(data & (1 << 11));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) input_report_abs(input, ABS_X, x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) input_report_abs(input, ABS_Y, y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) input_report_key(input, BTN_A, data & (1 << 7));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) input_report_key(input, BTN_B, data & (1 << 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) input_report_key(input, BTN_X, data & (1 << 9));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) input_report_key(input, BTN_Y, data & (1 << 10));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) input_report_key(input, BTN_START, data & (1 << 15));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) input_report_key(input, BTN_SELECT, data & (1 << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) input_sync(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static int ims_pcu_setup_gamepad(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct ims_pcu_gamepad *gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) gamepad = kzalloc(sizeof(struct ims_pcu_gamepad), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!gamepad || !input) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) "Not enough memory for gamepad device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) goto err_free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) gamepad->input = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) snprintf(gamepad->name, sizeof(gamepad->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) "IMS PCU#%d Gamepad Interface", pcu->device_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) usb_make_path(pcu->udev, gamepad->phys, sizeof(gamepad->phys));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) strlcat(gamepad->phys, "/input1", sizeof(gamepad->phys));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) input->name = gamepad->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) input->phys = gamepad->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) usb_to_input_id(pcu->udev, &input->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) input->dev.parent = &pcu->ctrl_intf->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) __set_bit(EV_KEY, input->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) __set_bit(BTN_A, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) __set_bit(BTN_B, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) __set_bit(BTN_X, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) __set_bit(BTN_Y, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) __set_bit(BTN_START, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) __set_bit(BTN_SELECT, input->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) __set_bit(EV_ABS, input->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) input_set_abs_params(input, ABS_X, -1, 1, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) input_set_abs_params(input, ABS_Y, -1, 1, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) "Failed to register gamepad input device: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) goto err_free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) pcu->gamepad = gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) err_free_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) kfree(gamepad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct ims_pcu_gamepad *gamepad = pcu->gamepad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) input_unregister_device(gamepad->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) kfree(gamepad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * PCU Communication protocol handling *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) #define IMS_PCU_PROTOCOL_STX 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) #define IMS_PCU_PROTOCOL_ETX 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) #define IMS_PCU_PROTOCOL_DLE 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* PCU commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) #define IMS_PCU_CMD_STATUS 0xa0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) #define IMS_PCU_CMD_PCU_RESET 0xa1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) #define IMS_PCU_CMD_RESET_REASON 0xa2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) #define IMS_PCU_CMD_SEND_BUTTONS 0xa3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) #define IMS_PCU_CMD_JUMP_TO_BTLDR 0xa4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) #define IMS_PCU_CMD_GET_INFO 0xa5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) #define IMS_PCU_CMD_SET_BRIGHTNESS 0xa6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) #define IMS_PCU_CMD_EEPROM 0xa7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) #define IMS_PCU_CMD_GET_FW_VERSION 0xa8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) #define IMS_PCU_CMD_GET_BL_VERSION 0xa9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) #define IMS_PCU_CMD_SET_INFO 0xab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) #define IMS_PCU_CMD_GET_BRIGHTNESS 0xac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) #define IMS_PCU_CMD_GET_DEVICE_ID 0xae
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) #define IMS_PCU_CMD_SPECIAL_INFO 0xb0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) #define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) #define IMS_PCU_CMD_OFN_SET_CONFIG 0xb3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) #define IMS_PCU_CMD_OFN_GET_CONFIG 0xb4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /* PCU responses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) #define IMS_PCU_RSP_STATUS 0xc0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) #define IMS_PCU_RSP_PCU_RESET 0 /* Originally 0xc1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) #define IMS_PCU_RSP_RESET_REASON 0xc2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) #define IMS_PCU_RSP_SEND_BUTTONS 0xc3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) #define IMS_PCU_RSP_JUMP_TO_BTLDR 0 /* Originally 0xc4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) #define IMS_PCU_RSP_GET_INFO 0xc5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) #define IMS_PCU_RSP_SET_BRIGHTNESS 0xc6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) #define IMS_PCU_RSP_EEPROM 0xc7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) #define IMS_PCU_RSP_GET_FW_VERSION 0xc8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) #define IMS_PCU_RSP_GET_BL_VERSION 0xc9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) #define IMS_PCU_RSP_SET_INFO 0xcb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) #define IMS_PCU_RSP_GET_BRIGHTNESS 0xcc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) #define IMS_PCU_RSP_CMD_INVALID 0xcd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) #define IMS_PCU_RSP_GET_DEVICE_ID 0xce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) #define IMS_PCU_RSP_SPECIAL_INFO 0xd0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) #define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) #define IMS_PCU_RSP_OFN_SET_CONFIG 0xd2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) #define IMS_PCU_RSP_OFN_GET_CONFIG 0xd3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) #define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) #define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) #define IMS_PCU_MIN_PACKET_LEN 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) #define IMS_PCU_DATA_OFFSET 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) #define IMS_PCU_CMD_WRITE_TIMEOUT 100 /* msec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) #define IMS_PCU_CMD_RESPONSE_TIMEOUT 500 /* msec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) static void ims_pcu_report_events(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) u32 data = get_unaligned_be32(&pcu->read_buf[3]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) ims_pcu_buttons_report(pcu, data & ~IMS_PCU_GAMEPAD_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (pcu->gamepad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) ims_pcu_gamepad_report(pcu, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static void ims_pcu_handle_response(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) switch (pcu->read_buf[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) case IMS_PCU_RSP_EVNT_BUTTONS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (likely(pcu->setup_complete))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) ims_pcu_report_events(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * See if we got command completion.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * If both the sequence and response code match save
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * the data and signal completion.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (pcu->read_buf[0] == pcu->expected_response &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) pcu->read_buf[1] == pcu->ack_id - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) memcpy(pcu->cmd_buf, pcu->read_buf, pcu->read_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) pcu->cmd_buf_len = pcu->read_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) complete(&pcu->cmd_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) for (i = 0; i < urb->actual_length; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) u8 data = pcu->urb_in_buf[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /* Skip everything until we get Start Xmit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (!pcu->have_stx && data != IMS_PCU_PROTOCOL_STX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (pcu->have_dle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) pcu->have_dle = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) pcu->read_buf[pcu->read_pos++] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) pcu->check_sum += data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) switch (data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) case IMS_PCU_PROTOCOL_STX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (pcu->have_stx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) dev_warn(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) "Unexpected STX at byte %d, discarding old data\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) pcu->read_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) pcu->have_stx = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) pcu->have_dle = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pcu->read_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) pcu->check_sum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) case IMS_PCU_PROTOCOL_DLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pcu->have_dle = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) case IMS_PCU_PROTOCOL_ETX:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (pcu->read_pos < IMS_PCU_MIN_PACKET_LEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) dev_warn(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) "Short packet received (%d bytes), ignoring\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) pcu->read_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) } else if (pcu->check_sum != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) dev_warn(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) "Invalid checksum in packet (%d bytes), ignoring\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) pcu->read_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) ims_pcu_handle_response(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) pcu->have_stx = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) pcu->have_dle = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) pcu->read_pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) pcu->read_buf[pcu->read_pos++] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) pcu->check_sum += data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static bool ims_pcu_byte_needs_escape(u8 byte)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return byte == IMS_PCU_PROTOCOL_STX ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) byte == IMS_PCU_PROTOCOL_ETX ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) byte == IMS_PCU_PROTOCOL_DLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static int ims_pcu_send_cmd_chunk(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) u8 command, int chunk, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) error = usb_bulk_msg(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) usb_sndbulkpipe(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) pcu->ep_out->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) pcu->urb_out_buf, len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) NULL, IMS_PCU_CMD_WRITE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) dev_dbg(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) "Sending 0x%02x command failed at chunk %d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) command, chunk, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) static int ims_pcu_send_command(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) u8 command, const u8 *data, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) int chunk = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) int delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) u8 csum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) u8 ack_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_STX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /* We know the command need not be escaped */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) pcu->urb_out_buf[count++] = command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) csum += command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) ack_id = pcu->ack_id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (ack_id == 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) ack_id = pcu->ack_id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (ims_pcu_byte_needs_escape(ack_id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) pcu->urb_out_buf[count++] = ack_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) csum += ack_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) for (i = 0; i < len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) delta = ims_pcu_byte_needs_escape(data[i]) ? 2 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (count + delta >= pcu->max_out_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) error = ims_pcu_send_cmd_chunk(pcu, command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) ++chunk, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (delta == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) pcu->urb_out_buf[count++] = data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) csum += data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) csum = 1 + ~csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) delta = ims_pcu_byte_needs_escape(csum) ? 3 : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (count + delta >= pcu->max_out_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) error = ims_pcu_send_cmd_chunk(pcu, command, ++chunk, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (delta == 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) pcu->urb_out_buf[count++] = csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_ETX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return ims_pcu_send_cmd_chunk(pcu, command, ++chunk, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) static int __ims_pcu_execute_command(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) u8 command, const void *data, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) u8 expected_response, int response_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) pcu->expected_response = expected_response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) init_completion(&pcu->cmd_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) error = ims_pcu_send_command(pcu, command, data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (expected_response &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) !wait_for_completion_timeout(&pcu->cmd_done,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) msecs_to_jiffies(response_time))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) dev_dbg(pcu->dev, "Command 0x%02x timed out\n", command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) #define ims_pcu_execute_command(pcu, code, data, len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) __ims_pcu_execute_command(pcu, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) IMS_PCU_CMD_##code, data, len, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) IMS_PCU_RSP_##code, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) IMS_PCU_CMD_RESPONSE_TIMEOUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) #define ims_pcu_execute_query(pcu, code) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ims_pcu_execute_command(pcu, code, NULL, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* Bootloader commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) #define IMS_PCU_BL_CMD_QUERY_DEVICE 0xa1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) #define IMS_PCU_BL_CMD_UNLOCK_CONFIG 0xa2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) #define IMS_PCU_BL_CMD_ERASE_APP 0xa3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) #define IMS_PCU_BL_CMD_PROGRAM_DEVICE 0xa4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) #define IMS_PCU_BL_CMD_PROGRAM_COMPLETE 0xa5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) #define IMS_PCU_BL_CMD_READ_APP 0xa6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) #define IMS_PCU_BL_CMD_RESET_DEVICE 0xa7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) #define IMS_PCU_BL_CMD_LAUNCH_APP 0xa8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) /* Bootloader commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) #define IMS_PCU_BL_RSP_QUERY_DEVICE 0xc1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) #define IMS_PCU_BL_RSP_UNLOCK_CONFIG 0xc2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) #define IMS_PCU_BL_RSP_ERASE_APP 0xc3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) #define IMS_PCU_BL_RSP_PROGRAM_DEVICE 0xc4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) #define IMS_PCU_BL_RSP_PROGRAM_COMPLETE 0xc5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) #define IMS_PCU_BL_RSP_READ_APP 0xc6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) #define IMS_PCU_BL_RSP_RESET_DEVICE 0 /* originally 0xa7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) #define IMS_PCU_BL_RSP_LAUNCH_APP 0 /* originally 0xa8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) #define IMS_PCU_BL_DATA_OFFSET 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static int __ims_pcu_execute_bl_command(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) u8 command, const void *data, size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) u8 expected_response, int response_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) pcu->cmd_buf[0] = command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) memcpy(&pcu->cmd_buf[1], data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) error = __ims_pcu_execute_command(pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) IMS_PCU_CMD_BOOTLOADER, pcu->cmd_buf, len + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) expected_response ? IMS_PCU_RSP_BOOTLOADER : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) response_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) "Failure when sending 0x%02x command to bootloader, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) pcu->cmd_buf[0], error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (expected_response && pcu->cmd_buf[2] != expected_response) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) "Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) pcu->cmd_buf[2], expected_response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) #define ims_pcu_execute_bl_command(pcu, code, data, len, timeout) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) __ims_pcu_execute_bl_command(pcu, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) IMS_PCU_BL_CMD_##code, data, len, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) IMS_PCU_BL_RSP_##code, timeout) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) #define IMS_PCU_INFO_PART_OFFSET 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) #define IMS_PCU_INFO_DOM_OFFSET 17
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) #define IMS_PCU_INFO_SERIAL_OFFSET 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) #define IMS_PCU_SET_INFO_SIZE 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) static int ims_pcu_get_info(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) error = ims_pcu_execute_query(pcu, GET_INFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) "GET_INFO command failed, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) memcpy(pcu->part_number,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) &pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) sizeof(pcu->part_number));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) memcpy(pcu->date_of_manufacturing,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) &pcu->cmd_buf[IMS_PCU_INFO_DOM_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) sizeof(pcu->date_of_manufacturing));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) memcpy(pcu->serial_number,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) &pcu->cmd_buf[IMS_PCU_INFO_SERIAL_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) sizeof(pcu->serial_number));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static int ims_pcu_set_info(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) memcpy(&pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) pcu->part_number, sizeof(pcu->part_number));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) memcpy(&pcu->cmd_buf[IMS_PCU_INFO_DOM_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) pcu->date_of_manufacturing, sizeof(pcu->date_of_manufacturing));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) memcpy(&pcu->cmd_buf[IMS_PCU_INFO_SERIAL_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) pcu->serial_number, sizeof(pcu->serial_number));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) error = ims_pcu_execute_command(pcu, SET_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) &pcu->cmd_buf[IMS_PCU_DATA_OFFSET],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) IMS_PCU_SET_INFO_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) "Failed to update device information, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) static int ims_pcu_switch_to_bootloader(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) /* Execute jump to the bootoloader */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) error = ims_pcu_execute_command(pcu, JUMP_TO_BTLDR, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) "Failure when sending JUMP TO BOOLTLOADER command, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) * Firmware Update handling *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) #define IMS_PCU_FIRMWARE_NAME "imspcu.fw"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) struct ims_pcu_flash_fmt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) __le32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) u8 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) u8 data[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) static unsigned int ims_pcu_count_fw_records(const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) const struct ihex_binrec *rec = (const struct ihex_binrec *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) unsigned int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) while (rec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) rec = ihex_next_binrec(rec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) static int ims_pcu_verify_block(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) u32 addr, u8 len, const u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) struct ims_pcu_flash_fmt *fragment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) fragment = (void *)&pcu->cmd_buf[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) put_unaligned_le32(addr, &fragment->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) fragment->len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) error = ims_pcu_execute_bl_command(pcu, READ_APP, NULL, 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) IMS_PCU_CMD_RESPONSE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) "Failed to retrieve block at 0x%08x, len %d, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) addr, len, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) fragment = (void *)&pcu->cmd_buf[IMS_PCU_BL_DATA_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) if (get_unaligned_le32(&fragment->addr) != addr ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) fragment->len != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) "Wrong block when retrieving 0x%08x (0x%08x), len %d (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) addr, get_unaligned_le32(&fragment->addr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) len, fragment->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (memcmp(fragment->data, data, len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) "Mismatch in block at 0x%08x, len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) addr, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) static int ims_pcu_flash_firmware(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) unsigned int n_fw_records)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) const struct ihex_binrec *rec = (const struct ihex_binrec *)fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct ims_pcu_flash_fmt *fragment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) unsigned int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) u32 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) u8 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) error = ims_pcu_execute_bl_command(pcu, ERASE_APP, NULL, 0, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) "Failed to erase application image, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) while (rec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) * The firmware format is messed up for some reason.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) * The address twice that of what is needed for some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) * reason and we end up overwriting half of the data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) * with the next record.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) addr = be32_to_cpu(rec->addr) / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) len = be16_to_cpu(rec->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) fragment = (void *)&pcu->cmd_buf[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) put_unaligned_le32(addr, &fragment->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) fragment->len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) memcpy(fragment->data, rec->data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) error = ims_pcu_execute_bl_command(pcu, PROGRAM_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) NULL, len + 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) IMS_PCU_CMD_RESPONSE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) "Failed to write block at 0x%08x, len %d, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) addr, len, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) if (addr >= pcu->fw_start_addr && addr < pcu->fw_end_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) error = ims_pcu_verify_block(pcu, addr, len, rec->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) pcu->update_firmware_status = (count * 100) / n_fw_records;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) rec = ihex_next_binrec(rec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) error = ims_pcu_execute_bl_command(pcu, PROGRAM_COMPLETE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) NULL, 0, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) "Failed to send PROGRAM_COMPLETE, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) static int ims_pcu_handle_firmware_update(struct ims_pcu *pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) unsigned int n_fw_records;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) int retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) dev_info(pcu->dev, "Updating firmware %s, size: %zu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) IMS_PCU_FIRMWARE_NAME, fw->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) n_fw_records = ims_pcu_count_fw_records(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) retval = ims_pcu_flash_firmware(pcu, fw, n_fw_records);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) retval = ims_pcu_execute_bl_command(pcu, LAUNCH_APP, NULL, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (retval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) "Failed to start application image, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) pcu->update_firmware_status = retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) sysfs_notify(&pcu->dev->kobj, NULL, "update_firmware_status");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) static void ims_pcu_process_async_firmware(const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) struct ims_pcu *pcu = context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if (!fw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) dev_err(pcu->dev, "Failed to get firmware %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) IMS_PCU_FIRMWARE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) error = ihex_validate_fw(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) dev_err(pcu->dev, "Firmware %s is invalid\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) IMS_PCU_FIRMWARE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) ims_pcu_handle_firmware_update(pcu, fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) complete(&pcu->async_firmware_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) * Backlight LED device support *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) #define IMS_PCU_MAX_BRIGHTNESS 31998
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static int ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) struct ims_pcu_backlight *backlight =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) container_of(cdev, struct ims_pcu_backlight, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) struct ims_pcu *pcu =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) container_of(backlight, struct ims_pcu, backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) __le16 br_val = cpu_to_le16(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) error = ims_pcu_execute_command(pcu, SET_BRIGHTNESS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) &br_val, sizeof(br_val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (error && error != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) dev_warn(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) "Failed to set desired brightness %u, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) value, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) static enum led_brightness
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) ims_pcu_backlight_get_brightness(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) struct ims_pcu_backlight *backlight =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) container_of(cdev, struct ims_pcu_backlight, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) struct ims_pcu *pcu =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) container_of(backlight, struct ims_pcu, backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) int brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) error = ims_pcu_execute_query(pcu, GET_BRIGHTNESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) dev_warn(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) "Failed to get current brightness, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) /* Assume the LED is OFF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) brightness =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) get_unaligned_le16(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) static int ims_pcu_setup_backlight(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) struct ims_pcu_backlight *backlight = &pcu->backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) snprintf(backlight->name, sizeof(backlight->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) "pcu%d::kbd_backlight", pcu->device_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) backlight->cdev.name = backlight->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) backlight->cdev.max_brightness = IMS_PCU_MAX_BRIGHTNESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) backlight->cdev.brightness_get = ims_pcu_backlight_get_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) backlight->cdev.brightness_set_blocking =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) ims_pcu_backlight_set_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) error = led_classdev_register(pcu->dev, &backlight->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) "Failed to register backlight LED device, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) static void ims_pcu_destroy_backlight(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct ims_pcu_backlight *backlight = &pcu->backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) led_classdev_unregister(&backlight->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * Sysfs attributes handling *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) struct ims_pcu_attribute {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) struct device_attribute dattr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) size_t field_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) int field_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) static ssize_t ims_pcu_attribute_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) struct ims_pcu_attribute *attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) container_of(dattr, struct ims_pcu_attribute, dattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) char *field = (char *)pcu + attr->field_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) return scnprintf(buf, PAGE_SIZE, "%.*s\n", attr->field_length, field);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) static ssize_t ims_pcu_attribute_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) struct ims_pcu_attribute *attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) container_of(dattr, struct ims_pcu_attribute, dattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) char *field = (char *)pcu + attr->field_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) size_t data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) if (count > attr->field_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) data_len = strnlen(buf, attr->field_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (data_len > attr->field_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) error = mutex_lock_interruptible(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) memset(field, 0, attr->field_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) memcpy(field, buf, data_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) error = ims_pcu_set_info(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) * Even if update failed, let's fetch the info again as we just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) * clobbered one of the fields.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) ims_pcu_get_info(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) return error < 0 ? error : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) #define IMS_PCU_ATTR(_field, _mode) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) struct ims_pcu_attribute ims_pcu_attr_##_field = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) .dattr = __ATTR(_field, _mode, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) ims_pcu_attribute_show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) ims_pcu_attribute_store), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) .field_offset = offsetof(struct ims_pcu, _field), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) .field_length = sizeof(((struct ims_pcu *)NULL)->_field), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) #define IMS_PCU_RO_ATTR(_field) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) IMS_PCU_ATTR(_field, S_IRUGO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) #define IMS_PCU_RW_ATTR(_field) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) IMS_PCU_ATTR(_field, S_IRUGO | S_IWUSR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) static IMS_PCU_RW_ATTR(part_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) static IMS_PCU_RW_ATTR(serial_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) static IMS_PCU_RW_ATTR(date_of_manufacturing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) static IMS_PCU_RO_ATTR(fw_version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) static IMS_PCU_RO_ATTR(bl_version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) static IMS_PCU_RO_ATTR(reset_reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) static ssize_t ims_pcu_reset_device(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) static const u8 reset_byte = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) error = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) if (value != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) dev_info(pcu->dev, "Attempting to reset device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) error = ims_pcu_execute_command(pcu, PCU_RESET, &reset_byte, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) dev_info(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) "Failed to reset device, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) static DEVICE_ATTR(reset_device, S_IWUSR, NULL, ims_pcu_reset_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) static ssize_t ims_pcu_update_firmware_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) const struct firmware *fw = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) error = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) if (value != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) error = mutex_lock_interruptible(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) error = request_ihex_firmware(&fw, IMS_PCU_FIRMWARE_NAME, pcu->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) dev_err(pcu->dev, "Failed to request firmware %s, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) IMS_PCU_FIRMWARE_NAME, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) * If we are already in bootloader mode we can proceed with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) * flashing the firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) * If we are in application mode, then we need to switch into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) * bootloader mode, which will cause the device to disconnect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) * and reconnect as different device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) if (pcu->bootloader_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) error = ims_pcu_handle_firmware_update(pcu, fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) error = ims_pcu_switch_to_bootloader(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) return error ?: count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) static DEVICE_ATTR(update_firmware, S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) NULL, ims_pcu_update_firmware_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) ims_pcu_update_firmware_status_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) return scnprintf(buf, PAGE_SIZE, "%d\n", pcu->update_firmware_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) static DEVICE_ATTR(update_firmware_status, S_IRUGO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) ims_pcu_update_firmware_status_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) static struct attribute *ims_pcu_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) &ims_pcu_attr_part_number.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) &ims_pcu_attr_serial_number.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) &ims_pcu_attr_date_of_manufacturing.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) &ims_pcu_attr_fw_version.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) &ims_pcu_attr_bl_version.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) &ims_pcu_attr_reset_reason.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) &dev_attr_reset_device.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) &dev_attr_update_firmware.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) &dev_attr_update_firmware_status.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) static umode_t ims_pcu_is_attr_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) struct attribute *attr, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) struct device *dev = container_of(kobj, struct device, kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) umode_t mode = attr->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) if (pcu->bootloader_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) if (attr != &dev_attr_update_firmware_status.attr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) attr != &dev_attr_update_firmware.attr &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) attr != &dev_attr_reset_device.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) if (attr == &dev_attr_update_firmware_status.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) return mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) static const struct attribute_group ims_pcu_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) .is_visible = ims_pcu_is_attr_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) .attrs = ims_pcu_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) /* Support for a separate OFN attribute group */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) #define OFN_REG_RESULT_OFFSET 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) s16 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) &addr, sizeof(addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) /* We only need LSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) *data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) u8 buffer[] = { addr, data };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) s16 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) &buffer, sizeof(buffer));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) return scnprintf(buf, PAGE_SIZE, "%x\n", data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) u8 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) error = kstrtou8(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) return error ?: count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) u8 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) error = kstrtou8(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) pcu->ofn_reg_addr = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) struct ims_pcu_ofn_bit_attribute {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) struct device_attribute dattr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) u8 addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) u8 nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) struct ims_pcu_ofn_bit_attribute *attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) struct device_attribute *dattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) struct usb_interface *intf = to_usb_interface(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) struct ims_pcu_ofn_bit_attribute *attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) u8 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) error = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) if (value > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) mutex_lock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (!error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) if (value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) data |= 1U << attr->nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) data &= ~(1U << attr->nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) mutex_unlock(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) return error ?: count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) #define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) .dattr = __ATTR(_field, S_IWUSR | S_IRUGO, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) .addr = _addr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) .nr = _nr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) static IMS_PCU_OFN_BIT_ATTR(engine_enable, 0x60, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) static IMS_PCU_OFN_BIT_ATTR(speed_enable, 0x60, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) static IMS_PCU_OFN_BIT_ATTR(assert_enable, 0x60, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) static IMS_PCU_OFN_BIT_ATTR(xyquant_enable, 0x60, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) static IMS_PCU_OFN_BIT_ATTR(xyscale_enable, 0x60, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) static IMS_PCU_OFN_BIT_ATTR(scale_x2, 0x63, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) static IMS_PCU_OFN_BIT_ATTR(scale_y2, 0x63, 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) static struct attribute *ims_pcu_ofn_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) &dev_attr_reg_data.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) &dev_attr_reg_addr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) &ims_pcu_ofn_attr_engine_enable.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) &ims_pcu_ofn_attr_speed_enable.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) &ims_pcu_ofn_attr_assert_enable.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) &ims_pcu_ofn_attr_xyquant_enable.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) &ims_pcu_ofn_attr_xyscale_enable.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) &ims_pcu_ofn_attr_scale_x2.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) &ims_pcu_ofn_attr_scale_y2.dattr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) static const struct attribute_group ims_pcu_ofn_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) .name = "ofn",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) .attrs = ims_pcu_ofn_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) static void ims_pcu_irq(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) struct ims_pcu *pcu = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) int retval, status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) status = urb->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) switch (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) /* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) case -ECONNRESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) case -ENOENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) case -ESHUTDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) /* this urb is terminated, clean up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) dev_dbg(pcu->dev, "%s - urb shutting down with status: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) dev_dbg(pcu->dev, "%s - nonzero urb status received: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) __func__, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) dev_dbg(pcu->dev, "%s: received %d: %*ph\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) urb->actual_length, urb->actual_length, pcu->urb_in_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) if (urb == pcu->urb_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) ims_pcu_process_data(pcu, urb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) retval = usb_submit_urb(urb, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) if (retval && retval != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) dev_err(pcu->dev, "%s - usb_submit_urb failed with result %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) __func__, retval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) pcu->urb_in_buf = usb_alloc_coherent(pcu->udev, pcu->max_in_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) GFP_KERNEL, &pcu->read_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) if (!pcu->urb_in_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) "Failed to allocate memory for read buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) pcu->urb_in = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) if (!pcu->urb_in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) dev_err(pcu->dev, "Failed to allocate input URB\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) goto err_free_urb_in_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) pcu->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) pcu->urb_in->transfer_dma = pcu->read_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) usb_fill_bulk_urb(pcu->urb_in, pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) usb_rcvbulkpipe(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) pcu->ep_in->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) pcu->urb_in_buf, pcu->max_in_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) ims_pcu_irq, pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) * We are using usb_bulk_msg() for sending so there is no point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) * in allocating memory with usb_alloc_coherent().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) pcu->urb_out_buf = kmalloc(pcu->max_out_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) if (!pcu->urb_out_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) dev_err(pcu->dev, "Failed to allocate memory for write buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) goto err_free_in_urb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) pcu->urb_ctrl_buf = usb_alloc_coherent(pcu->udev, pcu->max_ctrl_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) GFP_KERNEL, &pcu->ctrl_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (!pcu->urb_ctrl_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) "Failed to allocate memory for read buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) goto err_free_urb_out_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) pcu->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) if (!pcu->urb_ctrl) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) dev_err(pcu->dev, "Failed to allocate input URB\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) goto err_free_urb_ctrl_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) pcu->urb_ctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) pcu->urb_ctrl->transfer_dma = pcu->ctrl_dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) usb_fill_int_urb(pcu->urb_ctrl, pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) usb_rcvintpipe(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) pcu->ep_ctrl->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) pcu->urb_ctrl_buf, pcu->max_ctrl_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) ims_pcu_irq, pcu, pcu->ep_ctrl->bInterval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) err_free_urb_ctrl_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) usb_free_coherent(pcu->udev, pcu->max_ctrl_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) pcu->urb_ctrl_buf, pcu->ctrl_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) err_free_urb_out_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) kfree(pcu->urb_out_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) err_free_in_urb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) usb_free_urb(pcu->urb_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) err_free_urb_in_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) usb_free_coherent(pcu->udev, pcu->max_in_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) pcu->urb_in_buf, pcu->read_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) static void ims_pcu_buffers_free(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) usb_kill_urb(pcu->urb_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) usb_free_urb(pcu->urb_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) usb_free_coherent(pcu->udev, pcu->max_out_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) pcu->urb_in_buf, pcu->read_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) kfree(pcu->urb_out_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) usb_kill_urb(pcu->urb_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) usb_free_urb(pcu->urb_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) usb_free_coherent(pcu->udev, pcu->max_ctrl_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) pcu->urb_ctrl_buf, pcu->ctrl_dma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) static const struct usb_cdc_union_desc *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) ims_pcu_get_cdc_union_desc(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) const void *buf = intf->altsetting->extra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) size_t buflen = intf->altsetting->extralen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) struct usb_cdc_union_desc *union_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) dev_err(&intf->dev, "Missing descriptor data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) if (!buflen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) dev_err(&intf->dev, "Zero length descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) while (buflen >= sizeof(*union_desc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) union_desc = (struct usb_cdc_union_desc *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) if (union_desc->bLength > buflen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) dev_err(&intf->dev, "Too large descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) dev_dbg(&intf->dev, "Found union header\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) if (union_desc->bLength >= sizeof(*union_desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) return union_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) dev_err(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) "Union descriptor too short (%d vs %zd)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) union_desc->bLength, sizeof(*union_desc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) buflen -= union_desc->bLength;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) buf += union_desc->bLength;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) dev_err(&intf->dev, "Missing CDC union descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) const struct usb_cdc_union_desc *union_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) struct usb_host_interface *alt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) union_desc = ims_pcu_get_cdc_union_desc(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) if (!union_desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) union_desc->bMasterInterface0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) if (!pcu->ctrl_intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) alt = pcu->ctrl_intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) if (alt->desc.bNumEndpoints < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) pcu->ep_ctrl = &alt->endpoint[0].desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) pcu->data_intf = usb_ifnum_to_if(pcu->udev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) union_desc->bSlaveInterface0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) if (!pcu->data_intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) alt = pcu->data_intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) if (alt->desc.bNumEndpoints != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) "Incorrect number of endpoints on data interface (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) alt->desc.bNumEndpoints);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) pcu->ep_out = &alt->endpoint[0].desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) if (!usb_endpoint_is_bulk_out(pcu->ep_out)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) "First endpoint on data interface is not BULK OUT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) pcu->max_out_size = usb_endpoint_maxp(pcu->ep_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (pcu->max_out_size < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) "Max OUT packet size is too small (%zd)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) pcu->max_out_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) pcu->ep_in = &alt->endpoint[1].desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) if (!usb_endpoint_is_bulk_in(pcu->ep_in)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) "Second endpoint on data interface is not BULK IN\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) pcu->max_in_size = usb_endpoint_maxp(pcu->ep_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) if (pcu->max_in_size < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) "Max IN packet size is too small (%zd)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) pcu->max_in_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) static int ims_pcu_start_io(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) error = usb_submit_urb(pcu->urb_ctrl, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) "Failed to start control IO - usb_submit_urb failed with result: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) error = usb_submit_urb(pcu->urb_in, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) "Failed to start IO - usb_submit_urb failed with result: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) usb_kill_urb(pcu->urb_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) static void ims_pcu_stop_io(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) usb_kill_urb(pcu->urb_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) usb_kill_urb(pcu->urb_ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) static int ims_pcu_line_setup(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) struct usb_host_interface *interface = pcu->ctrl_intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) struct usb_cdc_line_coding *line = (void *)pcu->cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) memset(line, 0, sizeof(*line));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) line->dwDTERate = cpu_to_le32(57600);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) line->bDataBits = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) USB_CDC_REQ_SET_LINE_CODING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) USB_TYPE_CLASS | USB_RECIP_INTERFACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) 0, interface->desc.bInterfaceNumber,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) line, sizeof(struct usb_cdc_line_coding),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) 5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) dev_err(pcu->dev, "Failed to set line coding, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) USB_CDC_REQ_SET_CONTROL_LINE_STATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) USB_TYPE_CLASS | USB_RECIP_INTERFACE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) 0x03, interface->desc.bInterfaceNumber,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) NULL, 0, 5000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) dev_err(pcu->dev, "Failed to set line state, error: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) static int ims_pcu_get_device_info(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) error = ims_pcu_get_info(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) error = ims_pcu_execute_query(pcu, GET_FW_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) "GET_FW_VERSION command failed, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) snprintf(pcu->fw_version, sizeof(pcu->fw_version),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) "%02d%02d%02d%02d.%c%c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) pcu->cmd_buf[6], pcu->cmd_buf[7]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) error = ims_pcu_execute_query(pcu, GET_BL_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) "GET_BL_VERSION command failed, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) snprintf(pcu->bl_version, sizeof(pcu->bl_version),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) "%02d%02d%02d%02d.%c%c",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) pcu->cmd_buf[6], pcu->cmd_buf[7]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) error = ims_pcu_execute_query(pcu, RESET_REASON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) "RESET_REASON command failed, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) snprintf(pcu->reset_reason, sizeof(pcu->reset_reason),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) "%02x", pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) dev_dbg(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) "P/N: %s, MD: %s, S/N: %s, FW: %s, BL: %s, RR: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) pcu->part_number,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) pcu->date_of_manufacturing,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) pcu->serial_number,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) pcu->fw_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) pcu->bl_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) pcu->reset_reason);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) static int ims_pcu_identify_type(struct ims_pcu *pcu, u8 *device_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) error = ims_pcu_execute_query(pcu, GET_DEVICE_ID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) "GET_DEVICE_ID command failed, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) *device_id = pcu->cmd_buf[IMS_PCU_DATA_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) dev_dbg(pcu->dev, "Detected device ID: %d\n", *device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) static atomic_t device_no = ATOMIC_INIT(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) const struct ims_pcu_device_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) error = ims_pcu_get_device_info(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) /* Device does not respond to basic queries, hopeless */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) error = ims_pcu_identify_type(pcu, &pcu->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) dev_err(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) "Failed to identify device, error: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) * Do not signal error, but do not create input nor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) * backlight devices either, let userspace figure this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) * out (flash a new firmware?).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) !ims_pcu_device_info[pcu->device_id].keymap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) /* Same as above, punt to userspace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) /* Device appears to be operable, complete initialization */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) pcu->device_no = atomic_inc_return(&device_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) error = sysfs_create_group(&pcu->dev->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) &ims_pcu_ofn_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) error = ims_pcu_setup_backlight(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) info = &ims_pcu_device_info[pcu->device_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) goto err_destroy_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) if (info->has_gamepad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) error = ims_pcu_setup_gamepad(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) goto err_destroy_buttons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) pcu->setup_complete = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) err_destroy_buttons:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) ims_pcu_destroy_buttons(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) err_destroy_backlight:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) ims_pcu_destroy_backlight(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) if (pcu->setup_complete) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) pcu->setup_complete = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) mb(); /* make sure flag setting is not reordered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) if (pcu->gamepad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) ims_pcu_destroy_gamepad(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) ims_pcu_destroy_buttons(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) ims_pcu_destroy_backlight(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) sysfs_remove_group(&pcu->dev->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) &ims_pcu_ofn_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) static int ims_pcu_init_bootloader_mode(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) error = ims_pcu_execute_bl_command(pcu, QUERY_DEVICE, NULL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) IMS_PCU_CMD_RESPONSE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) dev_err(pcu->dev, "Bootloader does not respond, aborting\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) pcu->fw_start_addr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 11]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) pcu->fw_end_addr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 15]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) dev_info(pcu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) "Device is in bootloader mode (addr 0x%08x-0x%08x), requesting firmware\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) pcu->fw_start_addr, pcu->fw_end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) error = request_firmware_nowait(THIS_MODULE, true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) IMS_PCU_FIRMWARE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) pcu->dev, GFP_KERNEL, pcu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) ims_pcu_process_async_firmware);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) /* This error is not fatal, let userspace have another chance */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) complete(&pcu->async_firmware_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) static void ims_pcu_destroy_bootloader_mode(struct ims_pcu *pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) /* Make sure our initial firmware request has completed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) wait_for_completion(&pcu->async_firmware_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) #define IMS_PCU_APPLICATION_MODE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) #define IMS_PCU_BOOTLOADER_MODE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) static struct usb_driver ims_pcu_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) static int ims_pcu_probe(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) struct usb_device *udev = interface_to_usbdev(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) struct ims_pcu *pcu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) pcu = kzalloc(sizeof(struct ims_pcu), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) if (!pcu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) pcu->dev = &intf->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) pcu->udev = udev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) pcu->bootloader_mode = id->driver_info == IMS_PCU_BOOTLOADER_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) mutex_init(&pcu->cmd_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) init_completion(&pcu->cmd_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) init_completion(&pcu->async_firmware_done);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) error = ims_pcu_parse_cdc_data(intf, pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) goto err_free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) error = usb_driver_claim_interface(&ims_pcu_driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) pcu->data_intf, pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) dev_err(&intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) "Unable to claim corresponding data interface: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) goto err_free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) usb_set_intfdata(pcu->ctrl_intf, pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) usb_set_intfdata(pcu->data_intf, pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) error = ims_pcu_buffers_alloc(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) goto err_unclaim_intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) error = ims_pcu_start_io(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) goto err_free_buffers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) error = ims_pcu_line_setup(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) goto err_stop_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) error = sysfs_create_group(&intf->dev.kobj, &ims_pcu_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) goto err_stop_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) error = pcu->bootloader_mode ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) ims_pcu_init_bootloader_mode(pcu) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) ims_pcu_init_application_mode(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) goto err_remove_sysfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) err_remove_sysfs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) err_stop_io:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) ims_pcu_stop_io(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) err_free_buffers:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) ims_pcu_buffers_free(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) err_unclaim_intf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) usb_driver_release_interface(&ims_pcu_driver, pcu->data_intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) err_free_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) kfree(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) static void ims_pcu_disconnect(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) struct usb_host_interface *alt = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) usb_set_intfdata(intf, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) * See if we are dealing with control or data interface. The cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) * happens when we unbind primary (control) interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) if (alt->desc.bInterfaceClass != USB_CLASS_COMM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) ims_pcu_stop_io(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) if (pcu->bootloader_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) ims_pcu_destroy_bootloader_mode(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) ims_pcu_destroy_application_mode(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) ims_pcu_buffers_free(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) kfree(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) static int ims_pcu_suspend(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) pm_message_t message)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) struct usb_host_interface *alt = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) if (alt->desc.bInterfaceClass == USB_CLASS_COMM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) ims_pcu_stop_io(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) static int ims_pcu_resume(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) struct ims_pcu *pcu = usb_get_intfdata(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) struct usb_host_interface *alt = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106) if (alt->desc.bInterfaceClass == USB_CLASS_COMM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) retval = ims_pcu_start_io(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) if (retval == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) retval = ims_pcu_line_setup(pcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) static const struct usb_device_id ims_pcu_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) USB_DEVICE_AND_INTERFACE_INFO(0x04d8, 0x0082,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) USB_CLASS_COMM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) USB_CDC_SUBCLASS_ACM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) USB_CDC_ACM_PROTO_AT_V25TER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) .driver_info = IMS_PCU_APPLICATION_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) USB_DEVICE_AND_INTERFACE_INFO(0x04d8, 0x0083,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) USB_CLASS_COMM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) USB_CDC_SUBCLASS_ACM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) USB_CDC_ACM_PROTO_AT_V25TER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) .driver_info = IMS_PCU_BOOTLOADER_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) static struct usb_driver ims_pcu_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) .name = "ims_pcu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) .id_table = ims_pcu_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) .probe = ims_pcu_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) .disconnect = ims_pcu_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) .suspend = ims_pcu_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) .resume = ims_pcu_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142) .reset_resume = ims_pcu_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) module_usb_driver(ims_pcu_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) MODULE_DESCRIPTION("IMS Passenger Control Unit driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) MODULE_LICENSE("GPL");