From 6f783130424675faa40da9774d39c6cdff331ca2 Mon Sep 17 00:00:00 2001 From: Kenny Kessler Date: Mon, 4 Dec 2017 09:53:44 -0600 Subject: [PATCH] motorola: dlkm: Add Cypress Capsense Add the Cypress Capsense DLKM. Change-Id: Ia38e38d0042431be56ed20ec800b9b70bca032c9 Signed-off-by: Kenny Kessler Reviewed-on: https://gerrit.mot.com/1099054 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Kenneth Kessler Submit-Approved: Jira Key --- drivers/misc/cypress/Android.mk | 8 + drivers/misc/cypress/DataFetch.c | 251 ++++ drivers/misc/cypress/DataFetch.h | 71 + drivers/misc/cypress/Kbuild | 13 + drivers/misc/cypress/Makefile | 11 + drivers/misc/cypress/ProgrammingSteps.c | 1405 +++++++++++++++++++ drivers/misc/cypress/ProgrammingSteps.h | 149 ++ drivers/misc/cypress/SWD_PacketLayer.c | 621 ++++++++ drivers/misc/cypress/SWD_PacketLayer.h | 100 ++ drivers/misc/cypress/SWD_PhysicalLayer.h | 180 +++ drivers/misc/cypress/SWD_UpperPacketLayer.c | 182 +++ drivers/misc/cypress/SWD_UpperPacketLayer.h | 72 + drivers/misc/cypress/Timeout.h | 81 ++ drivers/misc/cypress/cycapsense_hssp.h | 80 ++ drivers/misc/cypress/cyttsp_sar.h | 125 ++ drivers/misc/cypress/cyttsp_sar_mmi.c | 1382 ++++++++++++++++++ include/linux/hssp_programmer.h | 26 + 17 files changed, 4757 insertions(+) create mode 100644 drivers/misc/cypress/Android.mk create mode 100644 drivers/misc/cypress/DataFetch.c create mode 100644 drivers/misc/cypress/DataFetch.h create mode 100644 drivers/misc/cypress/Kbuild create mode 100644 drivers/misc/cypress/Makefile create mode 100644 drivers/misc/cypress/ProgrammingSteps.c create mode 100644 drivers/misc/cypress/ProgrammingSteps.h create mode 100644 drivers/misc/cypress/SWD_PacketLayer.c create mode 100644 drivers/misc/cypress/SWD_PacketLayer.h create mode 100644 drivers/misc/cypress/SWD_PhysicalLayer.h create mode 100644 drivers/misc/cypress/SWD_UpperPacketLayer.c create mode 100644 drivers/misc/cypress/SWD_UpperPacketLayer.h create mode 100644 drivers/misc/cypress/Timeout.h create mode 100644 drivers/misc/cypress/cycapsense_hssp.h create mode 100644 drivers/misc/cypress/cyttsp_sar.h create mode 100644 drivers/misc/cypress/cyttsp_sar_mmi.c create mode 100644 include/linux/hssp_programmer.h diff --git a/drivers/misc/cypress/Android.mk b/drivers/misc/cypress/Android.mk new file mode 100644 index 000000000000..c527d21e6122 --- /dev/null +++ b/drivers/misc/cypress/Android.mk @@ -0,0 +1,8 @@ +DLKM_DIR := motorola/kernel/modules +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := cyttsp_sar.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +include $(DLKM_DIR)/AndroidKernelModule.mk \ No newline at end of file diff --git a/drivers/misc/cypress/DataFetch.c b/drivers/misc/cypress/DataFetch.c new file mode 100644 index 000000000000..1c771852a5ac --- /dev/null +++ b/drivers/misc/cypress/DataFetch.c @@ -0,0 +1,251 @@ +/***************************************************************************** +* File Name: DataFetch.c +* Version 1.0 +* +* Description: +* This source file contains the functions to fetch data from the Hex image and +* load in to the arrays used for Programming. +* +* Owner: +* Tushar Rastogi, Application Engineer (tusr@cypress.com) +* +* Related Document: +* AN84858 - PSoC 4 Programming using an External Microcontroller (HSSP) +* +* Hardware Dependency: +* PSoC 5LP Development Kit - CY8CKIT-050 +* +* Code Tested With: +* PSoC Creator 2.2 +* ARM GCC 4.4.1 +* CY8CKIT-050 +* +* Note: +* The definitions of the functions used in this file will change based on the +* interface used to get Hex file data. +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. + +******************************************************************************/ + +/****************************************************************************** +* Header file Inclusion +******************************************************************************/ +#include "cycapsense_hssp.h" +#include "DataFetch.h" + +/****************************************************************************** +* Global Constant declaration +******************************************************************************/ + +/****************************************************************************** +* Function Definitions +******************************************************************************/ + +/***************************** USER ATTENTION REQUIRED ************************ +**************** DEPENDS ON INTERFACE USED TO GET HEX FILE DATA *************** +All the function definitions below should be modified based on the interface +used to get Hex file data to be programmed. If a protocol like I2C, UART is +used to get the hex file data, change the function definitions accordingly */ + +/****************************************************************************** +* Function Name: HEX_ReadSiliconId +******************************************************************************* +* +* Summary: +* Loads the Device Silicon ID data in to an array +* +* Parameters: +* unsigned long *hexSiliconId - Address of variable which will store the +* Silicon ID fetched +* +* Return: +* None. +* +* Note: +* Modify definition based on method of getting programming data +* +******************************************************************************/ +void HEX_ReadSiliconId(struct hex_info *inf, unsigned long *hexSiliconId) +{ + unsigned char i; + + if (!inf || !inf->m_data) + return; + + for (i = 0; i < SILICON_ID_BYTE_LENGTH; i++) { + *hexSiliconId = *hexSiliconId | + ((unsigned long)(inf->m_data[2 + i]) << (8 * i)); + } +} + +/****************************************************************************** +* Function Name: HEX_ReadRowData +******************************************************************************* +* +* Summary: +* Loads the row data from hex file in to an array +* +* Parameters: +* unsigned short rowCount - Flash row count for which the data has to be +* fetched +* unsigned char * rowData - Base address of array which will store the +* Flash row data fetched +* +* Return: +* None. +* +* Note: +* Modify definition based on the method of getting programming data +* +* REMOVE THIS LOGIC WHILE PORTING THE HSSP CODE TO OTHER HOST PROGRAMMER +* +******************************************************************************/ +void HEX_ReadRowData(struct hex_info *inf, unsigned short rowCount, + unsigned char *rowData) +{ + unsigned short i; /* Maximum value of 'i' can be 256 */ + + if (!inf || !inf->data) + return; + + for (i = 0; i < FLASH_ROW_BYTE_SIZE_HEX_FILE; i++) { + rowData[i] = + inf->data[i + rowCount * FLASH_ROW_BYTE_SIZE_HEX_FILE]; + } +} + +/****************************************************************************** +* Function Name: HEX_ReadChipProtectionData +******************************************************************************* +* +* Summary: +* Loads the Chip Protection data in to an array +* +* Parameters: +* +* unsigned char * chipProtectionData - Address of variable which will store +* the Chip Protection data fetched +* +* Return: +* None. +* +* Note: +* Modify definition based on the method of getting programming data +* +******************************************************************************/ +void HEX_ReadChipProtectionData(struct hex_info *inf, + unsigned char *chipProtectionData) +{ + if (inf) + *chipProtectionData = inf->cl_protection; + else + *chipProtectionData = 1; +} + +/****************************************************************************** +* Function Name: HEX_ReadRowProtectionData +******************************************************************************* +* +* Summary: +* Loads the Flash Row Protection data in to an array +* +* Parameters: +* +* unsigned char * rowProtectionData - Base address of array which will store +* the Flash Row Protection data fetched +* unsigned char rowProtectionByteSize - Size of flash row protection settings +* in bytes +* +* Return: +* None. +* +* Note: +* Modify definition based on the method of getting programming data +* +******************************************************************************/ +void HEX_ReadRowProtectionData(struct hex_info *inf, + unsigned char rowProtectionByteSize, + unsigned char *rowProtectionData) +{ + if (!inf || !inf->s_data) + return; + + memcpy(rowProtectionData, inf->s_data, rowProtectionByteSize); +} + +/****************************************************************************** +* Function Name: HEX_ReadChecksumData +******************************************************************************* +* +* Summary: +* Loads the Checksum data in to an array +* +* Parameters: +* unsigned short * checksumData - Base address of the array which will store +* the Checksum data fetched +* +* Return: +* None. +* +* Note: +* Modify definition based on the method of getting programming data +* +******************************************************************************/ +void HEX_ReadChecksumData(struct hex_info *inf, unsigned short *checksumData) +{ + if (!inf) + return; + *checksumData = inf->cs; +} + +/****************************************************************************** +* Function Name: GetFlashRowCount +******************************************************************************* +* +* Summary: +* Returns the total number of Flash rows in the target PSoC 4 device +* +* Parameters: +* None +* +* Return: +* unsigned short +* Total number of Flash rows in target PSoC 4 +* +* Note: +* The Flash row count is from the HexImage.h file. Modify the definition based +* on the method of getting programming data +* +******************************************************************************/ +unsigned short GetFlashRowCount(void) +{ + return NUMBER_OF_FLASH_ROWS_HEX_FILE; +} + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/DataFetch.h b/drivers/misc/cypress/DataFetch.h new file mode 100644 index 000000000000..2f5c75860822 --- /dev/null +++ b/drivers/misc/cypress/DataFetch.h @@ -0,0 +1,71 @@ +/****************************************************************************** +* File Name: DataFetch.h +* Version 1.0 +* +* Description: +* This header file contains the definitions for the size of Programming data, +* and declarations for the functions used in getting the Programming data +* from Hex file image. The fuction definitions in corresponding +* DataFetch.c file will have to be modified if the method of getting +* programming data is changed. +* +* Note: +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ +#ifndef __DATAFETCH_H +#define __DATAFETCH_H + +/****************************************************************************** +* Macro definitions +******************************************************************************/ + +/* The below definitions are not dependent on hex file and are always + constant */ +#define SILICON_ID_BYTE_LENGTH 4 +#define CHECKSUM_BYTE_LENGTH 2 +#define MAXIMUM_ROW_PROTECTION_BYTE_LENGTH 32 + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ +void HEX_ReadSiliconId(struct hex_info *inf, unsigned long *hexSiliconId); +void HEX_ReadRowData(struct hex_info *inf, unsigned short rowCount, + unsigned char *rowData); +void HEX_ReadChipProtectionData(struct hex_info *inf, + unsigned char *chipProtectionData); +void HEX_ReadRowProtectionData(struct hex_info *inf, + unsigned char rowProtectionByteSize, + unsigned char *rowProtectionData); +void HEX_ReadChecksumData(struct hex_info *inf, unsigned short *checksumData); +unsigned short GetFlashRowCount(void); + +#endif /* __DATAFETCH_H */ + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/Kbuild b/drivers/misc/cypress/Kbuild new file mode 100644 index 000000000000..8404ac5f0de6 --- /dev/null +++ b/drivers/misc/cypress/Kbuild @@ -0,0 +1,13 @@ +# add -Wall to try to catch everything we can. +EXTRA_CFLAGS += -Wall +EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include + +EXTRA_CFLAGS += -DCY8C40xx_FAMILY +KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../../sensors/Module.symvers + +cyttsp_sar-y := ProgrammingSteps.o \ + SWD_PacketLayer.o \ + SWD_UpperPacketLayer.o \ + DataFetch.o \ + cyttsp_sar_mmi.o +obj-m += cyttsp_sar.o \ No newline at end of file diff --git a/drivers/misc/cypress/Makefile b/drivers/misc/cypress/Makefile new file mode 100644 index 000000000000..62a13fd28500 --- /dev/null +++ b/drivers/misc/cypress/Makefile @@ -0,0 +1,11 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean + diff --git a/drivers/misc/cypress/ProgrammingSteps.c b/drivers/misc/cypress/ProgrammingSteps.c new file mode 100644 index 000000000000..c4a04d2e1575 --- /dev/null +++ b/drivers/misc/cypress/ProgrammingSteps.c @@ -0,0 +1,1405 @@ +/****************************************************************************** + * File Name: ProgrammingSteps.c + * Version 1.0 + * + * Description: + * This file provides the source code for the high level Programming functions + * used by the main code to program target PSoC 4 + * + * Owner: + * Tushar Rastogi, Application Engineer (tusr@cypress.com) + * + * Related Document: + * AN84858 - PSoC 4 Programming using an External Microcontroller (HSSP) + * + * Hardware Dependency: + * PSoC 5LP Development Kit - CY8CKIT-050 + * + * Code Tested With: + * PSoC Creator 2.2 + * ARM GCC 4.4.1 + * CY8CKIT-050 + * + ******************************************************************************* + * Copyright (2013), Cypress Semiconductor Corporation. + ******************************************************************************* + * This software is owned by Cypress Semiconductor Corporation (Cypress) and is + * protected by and subject to worldwide patent protection (United States and + * foreign), United States copyright laws and international treaty provisions. + * Cypress hereby grants to licensee a personal, non-exclusive, non-transferable + * license to copy, use, modify, create derivative works of, and compile the + * Cypress Source Code and derivative works for the sole purpose of creating + * custom software in support of licensee product to be used only in conjunction + * with a Cypress integrated circuit as specified in the applicable agreement. + * Any reproduction, modification, translation, compilation, or representation + * of this software except as specified above is prohibited without the express + * written permission of Cypress. + * + * Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH + * REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Cypress reserves the right to make changes without further notice to the + * materials described herein. Cypress does not assume any liability arising out + * of the application or use of any product or circuit described herein. Cypress + * does not authorize its products for use as critical components in life-support + * systems where a malfunction or failure may reasonably be expected to result in + * significant injury to the user. The inclusion of Cypress' product in a life- + * support systems application implies that the manufacturer assumes all risk of + * such use and in doing so indemnifies Cypress against all charges. Use may be + * limited by and subject to the applicable Cypress software license agreement. + ******************************************************************************/ + +/****************************************************************************** + * Header file Inclusion + ******************************************************************************/ +#include "ProgrammingSteps.h" +#include "SWD_PhysicalLayer.h" +#include "SWD_UpperPacketLayer.h" +#include "SWD_PacketLayer.h" +#include "DataFetch.h" +#include "Timeout.h" + +/****************************************************************************** + * Global Variable definitions + ******************************************************************************/ +unsigned long checksum_Privileged; +unsigned long statusCode; + +unsigned char result; +unsigned char chipProtectionData_Chip; + +enum Transition_mode { OPEN_XXX, VIRGIN_OPEN, PROT_XXX, WRONG_TRANSITION } flow; + +/****************************************************************************** + * Function Definitions + ******************************************************************************/ + +/****************************************************************************** + * Function Name: PollSromStatus + ******************************************************************************* + * Summary: + * Polls the SROM_SYSREQ_BIT and SROM_PRIVILEGED_BIT in the CPUSS_SYSREQ + * register till it is reset or a timeout condition occurred, whichever is + * earlier. For a SROM polling timeout error, the timeout error status bit is + * set in swd_PacketAck variable and CPUSS_SYSARG register is read to get the + * error status code. If timeout does not happen, the CPUSS_SYSARG register is + * read to determine if the task executed successfully. + * + * Parameters: + * None. + * + * Return: + * SUCCESS - SROM executed the task successfully + * FAILURE - SROM task is not executed successfully and a timeout error occured. + * The failure code is stored in the statusCode global variable. + * + * Note: + * This function is called after non volatile memory operations like Read, + * Write of Flash, to check if SROM task has been executed which is indicated + * by SUCCESS. The status is read from the CPUSS_SYSARG register. + * + ******************************************************************************/ +unsigned char PollSromStatus(void) +{ + unsigned long time_elapsed = 0; + + do { + /* Read CPUSS_SYSREQ register and check if SROM_SYSREQ_BIT and + SROM_PRIVILEGED_BIT are reset to 0 */ + Read_IO(CPUSS_SYSREQ, &statusCode); + statusCode &= (SROM_SYSREQ_BIT | SROM_PRIVILEGED_BIT); + time_elapsed++; + } while ((statusCode != 0) && (time_elapsed <= SROM_POLLING_TIMEOUT)); + + /* If time exceeds the timeout value, set the SROM_TIMEOUT_ERROR bit in + swd_PacketAck */ + if (time_elapsed > SROM_POLLING_TIMEOUT) { + swd_PacketAck = swd_PacketAck | SROM_TIMEOUT_ERROR; + Read_IO(CPUSS_SYSARG, &statusCode); + return FAILURE; + } + + /* Read CPUSS_SYSARG register to check if the SROM command executed + successfully else set SROM_TIMEOUT_ERROR in swd_PacketAck */ + Read_IO(CPUSS_SYSARG, &statusCode); + + if ((statusCode & SROM_STATUS_SUCCESS_MASK) != SROM_STATUS_SUCCEEDED) { + swd_PacketAck = swd_PacketAck | SROM_TIMEOUT_ERROR; + return FAILURE; + } + + return SUCCESS; +} + +#if defined CY8C40xx_FAMILY +/****************************************************************************** + * Function Name: SetIMO48MHz + ******************************************************************************* + * Summary: + * Set IMO to 48 MHz + * + * Parameters: + * None. + * + * Return: + * None + * + * Note: + * This function is required to be called before any flash operation. + * This function sets the IMO to 48 MHz before flash write/erase operations + * and is part of the device acquire routine. + * + ******************************************************************************/ +void SetIMO48MHz(void) +{ + unsigned long parameter1 = 0; + + /* Load the Parameter1 with the SROM command to read silicon ID */ + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_SET_IMO_48MHZ) << + 8)); + + /* Write the command to CPUSS_SYSARG register */ + Write_IO(CPUSS_SYSARG, parameter1); + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_SET_IMO_48MHZ); +} +#endif +/****************************************************************************** + * Function Name: ReadSromStatus + ******************************************************************************* + * + * Summary: + * It reads the StatusCode global variable and returns LSB of this long variable + * to main.c. + * + * Parameters: + * None. + * + * Return: + * LSB of statusCode - LSB of statusCode global variable contains the error code + * + * Note: + * This function is called from main.c when SROM_TIMEOUT_ERROR bit is set in the + * swd_PacketAck. + * + ******************************************************************************/ + +unsigned char ReadSromStatus(void) +{ + return (unsigned char)statusCode; +} + +/****************************************************************************** + * Function Name: GetChipProtectionVal + ******************************************************************************* + * Summary: + * This sub-routine is used to read the Chip Protection Setting by using SROM + * System Calls. System call to read Silicon Id returns Chip protection settings + * in the CPUSS_SYSREQ register. The location of the data is bit [15:12] in the + * 32-bit register. + * + * Parameters: + * None. + * + * Return: + * chipProtectionData_Chip - 1 byte chip protection setting read from the chip + * + * Note: + * This function is called in the "Step 3. Erase All Flash" to read the chip + * protection settings to take decision whether to move the protection state + * to open and then erase the flash or directly erase the flash. + * + ******************************************************************************/ +unsigned char GetChipProtectionVal(struct hssp_data *d) +{ + unsigned long parameter1 = 0; + unsigned long chipProtData = 0; + + /* Load the Parameter1 with the SROM command to read silicon ID */ + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_GET_SILICON_ID) + << 8)); + + /* Write the command to CPUSS_SYSARG register */ + Write_IO(CPUSS_SYSARG, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request system call by writing to CPUSS_SYSREQ register */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_GET_SILICON_ID); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + /* Read CPUSS_SYSREQ register to get the current protection setting of + the chip */ + Read_IO(CPUSS_SYSREQ, &chipProtData); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + chipProtectionData_Chip = (unsigned char)(chipProtData >> 12); + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: GetTransitionMode + ******************************************************************************* + * + * Summary: + * It reads the chipProtectionData_Chip global variable which contains the Chip + * protection setting stored in the Chip and chipProtectionData_Hex from the + * hex file which contains the Chip protection setting stored in the HEX file. + * The function then validates if the two settings correspond to a valid + * transition. + * + * Parameters: + * None. + * + * Return: + * SUCCESS - Returns SUCCESS if the transition is valid. + * FAILURE - Returns Failure if the transition is invalid. + * Stores the transition in the global enum flow. + * + * Note: + * This function is called in "Step 3. Erase All Flash" to take decision on + * basis of the global enum flow. + * + ******************************************************************************/ +unsigned char GetTransitionMode(struct hssp_data *d) +{ + unsigned char chipProtectionData_Hex; + + /* Get the chip protection setting in the HEX file */ + HEX_ReadChipProtectionData(&d->inf, &chipProtectionData_Hex); + + /* enum variable flow stores the transition (current protection + setting to setting in hex file) of the chip */ + flow = WRONG_TRANSITION; + + switch (chipProtectionData_Chip) { + /* virgin to open protection setting is the only + allowed transition */ + case CHIP_PROT_VIRGIN: + if (chipProtectionData_Hex == CHIP_PROT_OPEN) + flow = VIRGIN_OPEN; + else + flow = WRONG_TRANSITION; + break; + + /* All transitions from Open are allowed other than + transition to virgin mode */ + case CHIP_PROT_OPEN: + if (chipProtectionData_Hex == CHIP_PROT_VIRGIN) + flow = WRONG_TRANSITION; + else + flow = OPEN_XXX; + break; + + /* Protected to Protected and Protected to Open are + the allowed transitions */ + case CHIP_PROT_PROTECTED: + if ((chipProtectionData_Hex == CHIP_PROT_OPEN) || + (chipProtectionData_Hex == CHIP_PROT_PROTECTED)) + flow = PROT_XXX; + else + flow = WRONG_TRANSITION; + break; + + default: + flow = WRONG_TRANSITION; + break; + } + + /* Set TRANSITION_ERROR bit high in Swd_PacketAck to show wrong + transition error */ + if (flow == WRONG_TRANSITION) { + swd_PacketAck = swd_PacketAck | TRANSITION_ERROR; + return FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: LoadLatch + ******************************************************************************* + * + * Summary: + * This function loads the page latch buffer with data to be programmed in to a + * row of flash. Data is loaded into the page latch buffer starting at the + * location specified by the SRAM_PARAMS_BASE input parameter. Data loaded into + * the page latch buffer will remain until a program operation is performed, + * which clears the page latch contents. + * + * Parameters: + * arrayID - Array Number of the flash + * rowData - Array containing 128 bytes of programming data + * + * Return: + * SUCCESS - Returns SUCCESS if Data is successfully latched + * FAILURE - Returns Failure if Data is not latched successfully + * + * Note: + * This function is called in "Step 5. Program Flash" and + * "Step 7. Program Protection Settings" to latch the programming data in SRAM. + * + ******************************************************************************/ +unsigned char LoadLatch(struct hssp_data *d, unsigned char arrayID, + unsigned char *rowData) +{ + unsigned long parameter1 = 0; + unsigned long parameter2 = 0; + unsigned char i = 0; + + /* Load parameter1 with the SROM command to load the page latch buffer + with programming data */ + parameter1 = ((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_LOAD_LATCH) << 8) + + (0x00 << 16) + ((unsigned long)arrayID << 24); + + /* Number of Bytes to load minus 1 */ + parameter2 = (FLASH_ROW_BYTE_SIZE_HEX_FILE - 1); + + /* Write parameter1 in SRAM */ + Write_IO(SRAM_PARAMS_BASE + 0x00, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Write parameter2 in SRAM */ + Write_IO(SRAM_PARAMS_BASE + 0x04, parameter2); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Put row data into SRAM buffer */ + for (i = 0; i < FLASH_ROW_BYTE_SIZE_HEX_FILE; i += 4) { + parameter1 = (rowData[i] << 0) + (rowData[i + 1] << 8) + + (rowData[i + 2] << 16) + (rowData[i + 3] << 24); + /* Write parameter1 in SRAM */ + Write_IO(SRAM_PARAMS_BASE + 0x08 + i, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + } + + /* Call "Load Latch" SROM API */ + + /* Set location of parameters */ + Write_IO(CPUSS_SYSARG, SRAM_PARAMS_BASE); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM operation */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_LOAD_LATCH); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: ChecksumAPI + ******************************************************************************* + * + * Summary: + * This function reads either the whole flash memory or a row of flash. When + * performing a checksum on the whole flash, the user code and the supervisory + * flash regions are included. When performing a checksum only on one row of + * flash, the flash row number is passed as a parameter. For computing Checksum + * of entire flash, ChecksumRow input parameter is loaded as macro + * CHECKSUM_ENTIRE_FLASH (0x8000). + * + * Parameters: + * checksumRow: Row number of flash for which checksum has to be calculated. + * To compute checksum of entire flash, + * this variable is set to + * CHECKSUM_ENTIRE_FLASH (0x8000). + * + * checksum: This variable is loaded with the checksum after the execution of + * the function. + * + * Return: + * SUCCESS - Returns SUCCESS if Checksum System call is successfully executed. + * FAILURE - Returns Failure if Checksum system call fails to execute. + * + * Note: + * This function is called in "Step 4. Checksum Privileged Calculation" and + * "Step 9. Verify Checksum" to calculate the checksum of flash privileged rows + * and entire flash, respectively. + * + ******************************************************************************/ +unsigned char ChecksumAPI(struct hssp_data *d, unsigned short checksumRow, + unsigned long *checksum) +{ + unsigned long parameter1 = 0; + unsigned long checksum_chip = 0; + + /* Load parameter1 with the SROM command to compute checksum of whole + flash */ + parameter1 = ((unsigned long)SROM_KEY1 << 00) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_CHECKSUM) << 8) + + (((unsigned long)checksumRow & 0x000000FF) << 16) + + (((unsigned long)checksumRow & 0x0000FF00) << 16); + + /* Load CPUSS_SYSARG register with parameter1 command */ + Write_IO(CPUSS_SYSARG, parameter1); + + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM operation */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_CHECKSUM); + + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + + if (result != SUCCESS) + return FAILURE; + + /* Read CPUSS_SYSARG register to get the checksum value */ + Read_IO(CPUSS_SYSARG, &checksum_chip); + + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* 28-bit checksum */ + *checksum = (checksum_chip & 0x0FFFFFFF); + + return SUCCESS; +} + +/****************************************************************************** + *Function Name: DeviceAcquire + ******************************************************************************* + * + * Summary: + * Acquire device with a alternate method which don't require >1.5Mhz SWD clock rate + * + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if the device is successfully acquired. + * FAILURE - Returns Failure if the function fails in any of the intermediate + * step. + * + * Note: + * This function has very strict timing requirements. The device must be + * acquired as per the timing requirements given in PSoC 4 Device Programming + * Specification Document. + * + ******************************************************************************/ + +#define DEVICE_ACQUIRE_TIMEOUT_ALTERNATE_METHOD 40 + +unsigned char DeviceAcquire(void) +{ + unsigned long chip_DAP_Id = 0; + unsigned short total_packet_count = 0; + unsigned long status = 0; + unsigned long reset_address = 0; + unsigned long psr_reg_val = 0; + unsigned long params = 0; + int i = 1; + + SetXresCmosOutput(); + SetXresHigh(); + + SetSwdckCmosOutput(); + SetSwdckLow(); + + SetSwdioCmosOutput(); + SetSwdioLow(); + + /* Execute SWD connect sequence. + 100 ms time out below is worst case time out value */ + do { + Swd_LineReset(); + Read_DAP(DPACC_DP_IDCODE_READ, &chip_DAP_Id); + total_packet_count++; + } while ((swd_PacketAck != SWD_OK_ACK) && + (total_packet_count < DEVICE_ACQUIRE_TIMEOUT_ALTERNATE_METHOD)); + + + /* Set PORT_ACQUIRE_TIMEOUT_ERROR bit in swd_PacketAck if time + exceeds 100 ms */ + if (total_packet_count == DEVICE_ACQUIRE_TIMEOUT_ALTERNATE_METHOD) { + swd_PacketAck = swd_PacketAck | PORT_ACQUIRE_TIMEOUT_ERROR; + return FAILURE; + } + + /* Set VERIFICATION_ERROR bit in swd_PacketAck if the DAP_ID read + from chip does not match with the ARM CM0_DAP_ID (MACRO defined in + ProgrammingSteps.h file - 0x0BB11477) */ + if ((chip_DAP_Id != CM0_DAP_ID) && (chip_DAP_Id != CM0PLUS_DAP_ID)) { + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + + /* Clear WDATAERR if any previous firmware upgrade operation was aborted in the mddle + and WDATAERR bit is set. This write is to the AP_ABORT register in Debug Port + (APnDP bit - 0, Address is 2'b00, Access -W for the AP ABORT register */ + Write_DAP(DPACC_DP_ABORT_WRITE, 0x00000008); + + /* Set the CSYSPWRUPEQ(System power up request), CDBGPRWUPREQ(debug power up request), + CDBGRSTREQ(Debug reset request) bits in the DP_CTRLSTAT regsiter) */ + Write_DAP(DPACC_DP_CTRLSTAT_WRITE, 0x54000000); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Set the AP register bank selection */ + Write_DAP(DPACC_DP_SELECT_WRITE, 0x00000000); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* set the register access as word 4-byte access + For device with CM0+ CPU, the HPROT[1] bit also needs to be set along with few other bits field */ + if (chip_DAP_Id == CM0PLUS_DAP_ID) { + Write_DAP(DPACC_AP_CSW_WRITE, 0x03000042); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + } + + /* Enable debug, and halt the CPU */ + Write_IO(0xE000EDF0, 0xA05F0003); + + /* Verify the debug enable, cpu halt bits are set */ + Read_IO(0xE000EDF0, &status); + if ((status & 0x00000003) != 0x00000003) + return FAILURE; + + /* Enable Breakpoint unit */ + Write_IO(0xE0002000, 0x00000003); + + /* Get address at reset vector */ + Read_IO(0x00000004, &reset_address); + + /* Map the address bits to the breakpoint compare register bit map, + Set the enable breakpoint bit, and the match bits */ + reset_address = (reset_address & 0x1FFFFFFC) | 0xC0000001; + + /* Update the breakpoint compare register */ + Write_IO(0xE0002008, reset_address); + + /* Issue software reset */ + Write_IO(0xE000ED0C, 0x05FA0004); + + /* Sufficient delay after reset for boot process, 5ms */ + while (i <= 50) { + DelayHundredUs(); + i++; + } + + /* Repeat a portion of the acquire sequence again */ + do { + Swd_LineReset(); + Read_DAP(DPACC_DP_IDCODE_READ, &chip_DAP_Id); + total_packet_count++; + } while ((swd_PacketAck != SWD_OK_ACK) && + (total_packet_count < DEVICE_ACQUIRE_TIMEOUT_ALTERNATE_METHOD)); + + + /* Set PORT_ACQUIRE_TIMEOUT_ERROR bit in swd_PacketAck if time + exceeds 100 ms */ + if (total_packet_count == DEVICE_ACQUIRE_TIMEOUT_ALTERNATE_METHOD) { + swd_PacketAck = swd_PacketAck | PORT_ACQUIRE_TIMEOUT_ERROR; + return FAILURE; + } + + /* Set VERIFICATION_ERROR bit in swd_PacketAck if the DAP_ID read + from chip does not match with the ARM CM0_DAP_ID (MACRO defined in + ProgrammingSteps.h file - 0x0BB11477) */ + if ((chip_DAP_Id != CM0_DAP_ID) && (chip_DAP_Id != CM0PLUS_DAP_ID)) { + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + + + /* Set the CSYSPWRUPEQ(System power up request), CDBGPRWUPREQ(debug power up request), + CDBGRSTREQ(Debug reset request) bits in the DP_CTRLSTAT regsiter) */ + Write_DAP(DPACC_DP_CTRLSTAT_WRITE, 0x54000000); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Set the AP register bank selection */ + Write_DAP(DPACC_DP_SELECT_WRITE, 0x00000000); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* set the register access as word 4-byte access + For device with CM0+ CPU, the HPROT[1] bit also needs to be set along with few other bits field */ + if (chip_DAP_Id == CM0PLUS_DAP_ID) { + Write_DAP(DPACC_AP_CSW_WRITE, 0x03000042); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + } + + /* Verify the debug enable, cpu halt bits are set */ + Read_IO(0xE000EDF0, &status); + if ((status & 0x00000003) != 0x00000003) + return FAILURE; + + /* Load infinite for loop code in SRAM address 0x20000300 */ + Write_IO(0x20000300, 0xE7FEE7FE); + + /* Load PC with address of infinite for loop SRAM address with thumb it(bit 0) set */ + Write_IO(0xE000EDF8, 0x20000301); + Write_IO(0xE000EDF4, 0x0001000F); + + /* Load SP with top of the SRAM address - set for mimimum SRAM size device(2KB size) */ + Write_IO(0xE000EDF8, 0x20000800); + Write_IO(0xE000EDF4, 0x00010011); + + /* Read xPSR regsiter, set the thumb bit, and store modified value to xPSR regsiter */ + Write_IO(0xE000EDF4, 0x00000010); + Read_IO(0xE000EDF8, &psr_reg_val); + psr_reg_val = psr_reg_val | 0x01000000; + Write_IO(0xE000EDF8, psr_reg_val); + Write_IO(0xE000EDF4, 0x00010010); + + /* Disable breakpoint unit */ + Write_IO(0xE0002000, 0x00000002); + + /* Unhalt CPU */ + Write_IO(0xE000EDF0, 0xA05F0001); + + /* The following SROM call to set IMO to 48MHZ must be skipped for PSOC 4100M, 4200M devices + Set "IMO=48MHZ" to enable Erase/Program/Write Flash operations. */ + params = ((unsigned long)SROM_KEY1 << 0) + (((unsigned long)SROM_KEY2 + (unsigned long)SROM_CMD_SET_IMO_48MHZ) << 8); + + /* Write Params in CPUSS_SYSARG */ + Write_IO(CPUSS_SYSARG, params); + + /* Request SROM call */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_SET_IMO_48MHZ); + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + + return SUCCESS; + +} + +/****************************************************************************** + * Function Name: VerifySiliconId + ******************************************************************************* + * + * Summary: + * This is Step 2 of the programming sequence. In this Step, Silicon Id of the + * PSoC 4 device is read and matched with the silicon id stored in the Hex File + * to verify that the correct device is being programmed. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if Silicon Id read from chip matches the Id in the + * HEX File. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char VerifySiliconId(struct hssp_data *d) +{ + unsigned char i; + unsigned long deviceSiliconID; + unsigned long hexSiliconId = 0; + unsigned long parameter1 = 0; + unsigned long siliconIdData1 = 0; + unsigned long siliconIdData2 = 0; + + /* Read and store Silicon ID from HEX file to hexSiliconId array */ + HEX_ReadSiliconId(&d->inf, &hexSiliconId); + + /* Load Parameter1 with the SROM command to read silicon ID from + PSoC 4 chip */ + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_GET_SILICON_ID) + << 8)); + + /* Load CPUSS_SYSARG register with parameter1 */ + Write_IO(CPUSS_SYSARG, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM operation */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_GET_SILICON_ID); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + /* Read CPUSS_SYSARG and CPUSS_SYSREQ to read 4 bytes of silicon ID */ + Read_IO(CPUSS_SYSARG, &siliconIdData1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + Read_IO(CPUSS_SYSREQ, &siliconIdData2); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* + SiliconIdData2 (0th byte) = 4th byte of Device Silicon ID (MSB) + SiliconIdData1 (3rd byte) = 3rd byte of Device Silicon ID + SiliconIdData1 (1st byte) = 2nd byte of Device Silicon ID + SiliconIdData1 (2nd byte) = 1st byte of Device Silicon ID (LSB) + */ + deviceSiliconID = (((siliconIdData2 << 24) & 0xFF000000) + + (siliconIdData1 & 0x00FF0000) + + ((siliconIdData1 << 8) & 0x0000FF00) + + ((siliconIdData1 >> 8) & 0x000000FF)); + + /* Match the Silicon ID read from HEX file and PSoC 4 chip */ + for (i = 0; i < SILICON_ID_BYTE_LENGTH; i++) { + if ((deviceSiliconID & 0xFF00FFFF) != + (hexSiliconId & 0xFF00FFFF)) { + /* Set the VERIFICATION_ERROR bit in swd_PacketAck */ + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + } + return SUCCESS; +} + +/****************************************************************************** + * Function Name: EraseAllFlash + ******************************************************************************* + * + * Summary: + * This is Step 3 of the programming sequence. In this Step, the whole user + * flash is erased. This function uses GetChipProtectionVal() and + * GetTransitionMode() API's to take the decision on the method to follow to + * erase the device. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully erases complete user + * flash region. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char EraseAllFlash(struct hssp_data *d) +{ + unsigned long parameter1 = 0; + + /* Get current chip protection setting */ + GetChipProtectionVal(d); + + /* Check if the Chip protection setting transition is valid */ + result = GetTransitionMode(d); + if (result != SUCCESS) + return FAILURE; + + /* If the transition is from open to any protection setting or from + virgin to open, call ERASE_ALL SROM command */ + if ((flow == OPEN_XXX) || (flow == VIRGIN_OPEN)) { + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long) + SROM_CMD_ERASE_ALL) << 8)); + + /* Load ERASE_ALL SROM command in parameter1 to SRAM */ + Write_IO(SRAM_PARAMS_BASE + 0x00, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Set location of parameters */ + Write_IO(CPUSS_SYSARG, SRAM_PARAMS_BASE); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM call */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_ERASE_ALL); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + } else if (flow == PROT_XXX) { + /* If the transition is from protected mode to open mode or + protected mode to protected mode only, + call ERASE_ALL SROM command */ + + /* Move chip to open state: 0x01 corresponds to open state, + 0x00 to macro 1 */ + parameter1 = ((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_WRITE_PROTECTION) << 8) + + (0x01 << 16) + (0x00 << 24); + + /* Load the write protection command to SRAM */ + Write_IO(CPUSS_SYSARG, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM call */ + Write_IO(CPUSS_SYSREQ, + SROM_SYSREQ_BIT | SROM_CMD_WRITE_PROTECTION); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + /* Re-acquire chip in OPEN mode */ + result = DeviceAcquire(); + if (result != SUCCESS) + return FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: ChecksumPrivileged + ******************************************************************************* + * + * Summary: + * This is Step 4 of the programming sequence. In this Step, checksum of the + * privileged rows is calulated using system call to determine checksum. This + * step uses ChecksumAPI() API to store the checksum of privileged rows in a + * Checksum_Privileged global variable. This variable is used in step 9 to + * calculate the checksum of user rows. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully calculated the checksum + * of privileged rows. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char ChecksumPrivileged(struct hssp_data *d) +{ + result = ChecksumAPI(d, CHECKSUM_ENTIRE_FLASH, &checksum_Privileged); + if (result != SUCCESS) + return FAILURE; + return SUCCESS; +} + +/****************************************************************************** + * Function Name: ProgramFlash + ******************************************************************************* + * + * Summary: + * This is Step 5 of the programming sequence. In this Step, the whole user + * flash is re-programmed with the programming data in the HEX File. This + * function uses LoadLatch() API to latch the row data in SRAM page latch buffer + * which is then programmed to the specific row using system calls to program + * row. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully programs entire flash + * region. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char ProgramFlash(struct hssp_data *d) +{ + unsigned char arrayID = 0; + unsigned char rowData[FLASH_ROW_BYTE_SIZE_HEX_FILE]; + unsigned short numOfFlashRows = 0; + unsigned short rowCount = 0; + unsigned long parameter1 = 0; + + /* Get the total number of flash rows in the Target PSoC 4 device */ + numOfFlashRows = GetFlashRowCount(); + + /* Program all flash rows */ + for (rowCount = 0; rowCount < numOfFlashRows; rowCount++) { + + HEX_ReadRowData(&d->inf, rowCount, &rowData[0]); + arrayID = rowCount / ROWS_PER_ARRAY; + result = LoadLatch(d, arrayID, &rowData[0]); + if (result != SUCCESS) + return FAILURE; + + /* Load parameter1 with Program Row - SROM command */ + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long) + SROM_CMD_PROGRAM_ROW) << 8) + + (((unsigned long)rowCount & + 0x000000FF) << 16) + + (((unsigned long)rowCount & + 0x0000FF00) << 16)); + + /* Write parameters in SRAM */ + Write_IO(SRAM_PARAMS_BASE + 0x00, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Set location of parameters */ + Write_IO(CPUSS_SYSARG, SRAM_PARAMS_BASE); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM operation */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_PROGRAM_ROW); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: VerifySwRevision + ******************************************************************************* + * + * Summary: + * This is a way to check Sw revision stored in flash at SW_REVISION_OFFSET. + * This is a preliminary step to avoid reflashing with the same SW revision. + * The checksum verification may not work because the checksun is changed is + * a configuration is stored in the flash. In this Step, flash region is + * directly read using Read_IO API defined in SWD_UpperPacketLayer.h and + * compared with the HEX File. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully verifies the software + * revision with the HEX File. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char VerifySwRevision(struct hssp_data *d) +{ + unsigned long flashData = 0; + unsigned short row; + unsigned short offset; + unsigned short HexSwRev; + unsigned short ChipSwRev; + unsigned char rowData[FLASH_ROW_BYTE_SIZE_HEX_FILE]; + + /* Get the Sw rev row in the Target PSoC 4 device */ + row = SW_REVISION_OFFSET / FLASH_ROW_BYTE_SIZE_HEX_FILE; + offset = SW_REVISION_OFFSET % FLASH_ROW_BYTE_SIZE_HEX_FILE; + + /* Extract row from the hex-file */ + HEX_ReadRowData(&d->inf, row, &rowData[0]); + + HexSwRev = (rowData[offset + 1]<<8) | rowData[offset]; + + /* Read flash via AHB-interface */ + Read_IO(SW_REVISION_OFFSET, &flashData); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + ChipSwRev = ((flashData >> (offset % 4)*8)) & 0x00FF; + ChipSwRev |= ((flashData >> (offset % 4 + 1) * 8) << 8) & 0xFF00; + d->sw_rev = HexSwRev; + + pr_info("cycapsense_hssp: File SW rev 0x%x, Flash SW rev 0x%x\n", + HexSwRev, ChipSwRev); + + if (HexSwRev != ChipSwRev) { + swd_PacketAck = swd_PacketAck|VERIFICATION_ERROR; + return FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: VerifyFlash + ******************************************************************************* + * + * Summary: + * This is Step 6 of the programming sequence. This is an optional step as we + * verify the checksum explicitly. In this Step, flash region is directly read + * using Read_IO API defined in SWD_UpperPacketLayer.h and compared with the + * HEX File. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully verifies the entire flash + * with the HEX File. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char VerifyFlash(struct hssp_data *d) +{ + unsigned long flashData = 0; + unsigned short numOfFlashRows = 0; + unsigned short rowAddress = 0; + unsigned short rowCount; + unsigned char i; + unsigned char rowData[FLASH_ROW_BYTE_SIZE_HEX_FILE]; + unsigned char chipData[FLASH_ROW_BYTE_SIZE_HEX_FILE]; + + /* Get the total number of flash rows in the Target PSoC 4 device */ + numOfFlashRows = GetFlashRowCount(); + + /* Read and Verify Flash rows */ + for (rowCount = 0; rowCount < numOfFlashRows; rowCount++) { + /* Read row from hex file */ + /* linear address of row in flash */ + rowAddress = FLASH_ROW_BYTE_SIZE_HEX_FILE * rowCount; + + /* Extract 128-byte row from the hex-file from address: + “rowCount” into buffer - “rowData”. */ + HEX_ReadRowData(&d->inf, rowCount, &rowData[0]); + + /* Read row from chip */ + for (i = 0; i < FLASH_ROW_BYTE_SIZE_HEX_FILE; i += 4) { + /* Read flash via AHB-interface */ + Read_IO(rowAddress + i, &flashData); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + chipData[i + 0] = (flashData >> 0) & 0xFF; + chipData[i + 1] = (flashData >> 8) & 0xFF; + chipData[i + 2] = (flashData >> 16) & 0xFF; + chipData[i + 3] = (flashData >> 24) & 0xFF; + } + + /* Compare the row data of HEX file with chip data */ + for (i = 0; i < FLASH_ROW_BYTE_SIZE_HEX_FILE; i++) { + if (chipData[i] != rowData[i]) { + swd_PacketAck = swd_PacketAck | + VERIFICATION_ERROR; + return FAILURE; + } + } + } + return SUCCESS; +} + +/****************************************************************************** + * Function Name: ProgramProtectionSettings + ******************************************************************************* + * + * Summary: + * This is Step 7 of the programming sequence. In this step, Chip protection + * settings and Row Protection settings are read from the HEX file and + * programmed to the specific loctions in the flash. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully writes the protection + * settings. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char ProgramProtectionSettings(struct hssp_data *d) +{ + unsigned char arrayID = 0; + unsigned char rowProtectionByteSize = 0; + unsigned char rowProtectionData[MAXIMUM_ROW_PROTECTION_BYTE_LENGTH]; + unsigned char chipProtectionData_Hex; + unsigned short numOfFlashRows = 0; + unsigned long parameter1 = 0; + + /* Get total number of flash rows to determine the size of + row protection data and arrayID */ + numOfFlashRows = GetFlashRowCount(); + + rowProtectionByteSize = numOfFlashRows / 8; + + arrayID = numOfFlashRows / ROWS_PER_ARRAY; + + HEX_ReadChipProtectionData(&d->inf, &chipProtectionData_Hex); + + HEX_ReadRowProtectionData(&d->inf, rowProtectionByteSize, + &rowProtectionData[0]); + + /* Load protection setting of current macro into volatile latch using + LoadLatch API */ + result = LoadLatch(d, arrayID, &rowProtectionData[0]); + if (result != SUCCESS) + return FAILURE; + + /* Program protection setting into supervisory row */ + parameter1 = (unsigned long)(((unsigned long)SROM_KEY1 << 0) + + (((unsigned long)SROM_KEY2 + + (unsigned long)SROM_CMD_WRITE_PROTECTION) + << 8) + + ((unsigned long)chipProtectionData_Hex << + 16)); + + /* Load parameter1 in CPUSS_SYSARG register */ + Write_IO(CPUSS_SYSARG, parameter1); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Request SROM call */ + Write_IO(CPUSS_SYSREQ, SROM_SYSREQ_BIT | SROM_CMD_WRITE_PROTECTION); + + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + /* Read status of the operation */ + result = PollSromStatus(); + if (result != SUCCESS) + return FAILURE; + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: VerifyProtectionSettings + ******************************************************************************* + * + * Summary: + * This is Step 8 of the programming sequence. In this step, Chip protection + * settings and Row Protection settings are read from the HEX file and verified + * with the protection settings programmed in flash. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully verifies the protection + * settings. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char VerifyProtectionSettings(struct hssp_data *d) +{ + unsigned long protectionData = 0; + unsigned long flashProtectionAddress = 0; + unsigned short numOfFlashRows = 0; + unsigned char chipProtectionData_Hex = 0; + unsigned char rowProtectionByteSize = 0; + unsigned char i; + unsigned char rowProtectionData[MAXIMUM_ROW_PROTECTION_BYTE_LENGTH]; + unsigned char + rowProtectionFlashData[MAXIMUM_ROW_PROTECTION_BYTE_LENGTH]; + + numOfFlashRows = GetFlashRowCount(); + + rowProtectionByteSize = numOfFlashRows / 8; + + flashProtectionAddress = SFLASH_MACRO; + + /* Read Protection settings from hex-file */ + HEX_ReadRowProtectionData(&d->inf, rowProtectionByteSize, + &rowProtectionData[0]); + + /* Read Protection settings from silicon */ + for (i = 0; i < rowProtectionByteSize; i += 4) { + + Read_IO(flashProtectionAddress + i, &protectionData); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + rowProtectionFlashData[i + 0] = (protectionData >> 0) & 0xFF; + rowProtectionFlashData[i + 1] = (protectionData >> 8) & 0xFF; + rowProtectionFlashData[i + 2] = (protectionData >> 16) & 0xFF; + rowProtectionFlashData[i + 3] = (protectionData >> 24) & 0xFF; + } + + /* Compare hex and silicon’s data */ + for (i = 0; i < rowProtectionByteSize; i++) { + + if (rowProtectionData[i] != rowProtectionFlashData[i]) { + /* Set the verification error bit for Flash + protection data mismatch and return failure */ + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + } + + /* Read Chip Level Protection from hex-file */ + HEX_ReadChipProtectionData(&d->inf, &chipProtectionData_Hex); + + /* Read Chip Level Protection from the silicon */ + Read_IO(SFLASH_CPUSS_PROTECTION, &protectionData); + if (swd_PacketAck != SWD_OK_ACK) + return FAILURE; + + chipProtectionData_Chip = (protectionData >> 24) & 0x0F; + if (chipProtectionData_Chip == CHIP_PROT_VIRGIN) + chipProtectionData_Chip = CHIP_PROT_OPEN; + else if (chipProtectionData_Chip == CHIP_PROT_OPEN) + chipProtectionData_Chip = CHIP_PROT_VIRGIN; + + /* Compare hex’s and silicon’s chip protection data */ + if (chipProtectionData_Chip != chipProtectionData_Hex) { + /* Set the verification error bit for Flash protection data + mismatch and return failure */ + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: VerifyChecksum + ******************************************************************************* + * + * Summary: + * This is Step 9 of the programming sequence. In this step, Checksum of user + * data in flash is verified with the Checksum stored in the HEX File. This step + * uses the Checksum of privileged rows calculated in Step 4 get the checksum + * of user data in flash. + * + * Parameters: + * None + * + * Return: + * SUCCESS - Returns SUCCESS if function successfully verifies the checksum. + * FAILURE - Returns Failure if any of the intermediate step returns a fail + * message. + * + * Note: + * + ******************************************************************************/ +unsigned char VerifyChecksum(struct hssp_data *d) +{ + unsigned long checksum_All = 0; + unsigned short chip_Checksum = 0; + unsigned short checksumData = 0; + + /* Read the checksum of entire flash */ + result = ChecksumAPI(d, CHECKSUM_ENTIRE_FLASH, &checksum_All); + if (result != SUCCESS) + return FAILURE; + + /* Calculate checksum of user flash */ + chip_Checksum = (unsigned short)checksum_All - + (unsigned short)checksum_Privileged; + d->chip_cs = chip_Checksum; + + /* Read checksum from hex file */ + HEX_ReadChecksumData(&d->inf, &checksumData); + + /* Compare the checksum data of silicon and hex file */ + if (chip_Checksum != checksumData) { + swd_PacketAck = swd_PacketAck | VERIFICATION_ERROR; + return FAILURE; + } + + return SUCCESS; +} + +/****************************************************************************** + * Function Name: ReadHsspErrorStatus + ******************************************************************************* + * + * Summary: + * Returns the HSSP Error status in case of FAILURE return in any one of the + * programming steps. + * + * Parameters: + * None. + * + * Return: + * swd_PacketAck - Each bit of this 8-bit return value has a specific meaning. + * + * Note: + * Refer to the application note pdf for details on the Error status bit + * definitions + ******************************************************************************/ +unsigned char ReadHsspErrorStatus(void) +{ + return swd_PacketAck; +} + +/****************************************************************************** + * Function Name: ExitProgrammingMode + ******************************************************************************* + * + * Summary: + * Releases the target PSoC 4 device from Programming mode. + * + * Parameters: + * None. + * + * Return: + * None. + * + * Note: + * + ******************************************************************************/ +void ExitProgrammingMode(void) +{ + /* Drive the SWDIO, SWDCK outputs low */ + SetSwdckLow(); + SetSwdioLow(); + + /* Make SWDIO, SWDCK High-Z after completing Programming */ + SetSwdioHizInput(); + SetSwdckHizInput(); + + /* Generate active low rest pulse for 100 uS */ + SetXresCmosOutput(); + SetXresLow(); + DelayHundredUs(); + SetXresHigh(); + + /* Make XRES High-Z after generating the reset pulse */ + SetXresHizInput(); +} + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/ProgrammingSteps.h b/drivers/misc/cypress/ProgrammingSteps.h new file mode 100644 index 000000000000..e31caa9e3fe7 --- /dev/null +++ b/drivers/misc/cypress/ProgrammingSteps.h @@ -0,0 +1,149 @@ +/****************************************************************************** +* File Name: ProgrammingSteps.h +* Version 1.0 +* +* Description: +* This header file contains high level definitions and function declarations +* associated with programming of the target PSoC 4 device +* +* Note: +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ + +#ifndef __PROGRAMMINGSTEPS_H +#define __PROGRAMMINGSTEPS_H + +#include "cycapsense_hssp.h" +/****************************************************************************** +* Macro definitions +******************************************************************************/ + +/* Return value definitions for high level Programming functions */ +#ifndef FAILURE +#define FAILURE 0 +#endif + +#ifndef SUCCESS +#define SUCCESS (!FAILURE) +#endif + +/* Return value of PollSromStatus function */ +#define SROM_SUCCESS 0x01 + +/* Error codes returned by Swd_PacketAck whenever any top-level step returns a + failure status*/ + +/* This bit field is set if programmer fails to acquire the device in 1.5 ms */ +#define PORT_ACQUIRE_TIMEOUT_ERROR 0x10 + +/* This bit field is set if the SROM does not return the success status code + within the SROM Polling timeout duration*/ +#define SROM_TIMEOUT_ERROR 0x20 + +/* This bit field is set in case of JTAG ID mismatch or Flash data verification + mismatch or Checksum data mismatch */ +#define VERIFICATION_ERROR 0x40 + +/* This bit field is set if wrong transition of chip protection settings is + detected */ +#define TRANSITION_ERROR 0x80 + +/* Constants for Address Space of CPU */ +#if defined CY8C40xx_FAMILY +#define CPUSS_SYSREQ 0x40100004 +#define CPUSS_SYSARG 0x40100008 +#else +#define CPUSS_SYSREQ 0x40000004 +#define CPUSS_SYSARG 0x40000008 +#endif +#define TEST_MODE 0x40030014 +#define SRAM_PARAMS_BASE 0x20000100 +#define SFLASH_MACRO 0x0FFFF000 +#define SFLASH_CPUSS_PROTECTION 0x0FFFF07C + +/* SROM Constants */ +#define SROM_KEY1 0xB6 +#define SROM_KEY2 0xD3 +#define SROM_SYSREQ_BIT 0x80000000 +#define SROM_PRIVILEGED_BIT 0x10000000 +#define SROM_STATUS_SUCCEEDED 0xA0000000 +#define SROM_STATUS_FAILED 0xF0000000 + +/* SROM Commands */ +#define SROM_CMD_GET_SILICON_ID 0x00 +#define SROM_CMD_LOAD_LATCH 0x04 +#define SROM_CMD_PROGRAM_ROW 0x06 +#define SROM_CMD_ERASE_ALL 0x0A +#define SROM_CMD_CHECKSUM 0x0B +#define SROM_CMD_WRITE_PROTECTION 0x0D +#if defined CY8C40xx_FAMILY +#define SROM_CMD_SET_IMO_48MHZ 0x15 +#endif + +/* Chip Level Protection */ +#define CHIP_PROT_VIRGIN 0x00 +#define CHIP_PROT_OPEN 0x01 +#define CHIP_PROT_PROTECTED 0x02 +#define CHIP_PROT_KILL 0x04 + +/* Mask for status code returned by polling SROM */ +#define SROM_STATUS_SUCCESS_MASK 0xF0000000 + +/* Constant for computing checksum of entire flash */ +#define CHECKSUM_ENTIRE_FLASH 0x8000 + +/* Constant DAP ID of ARM Cortex M0 CPU */ +#define CM0_DAP_ID 0x0BC11477 +#define CM0PLUS_DAP_ID 0x0BC11477 + +/* Constant maximum number of rows in PSoC 4 */ +#define ROWS_PER_ARRAY 256 + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ + +unsigned char DeviceAcquire(void); +unsigned char VerifySiliconId(struct hssp_data *d); +unsigned char EraseAllFlash(struct hssp_data *d); +unsigned char ChecksumPrivileged(struct hssp_data *d); +unsigned char ProgramFlash(struct hssp_data *d); +unsigned char VerifyFlash(struct hssp_data *d); +unsigned char ProgramProtectionSettings(struct hssp_data *d); +unsigned char VerifyProtectionSettings(struct hssp_data *d); +unsigned char VerifyChecksum(struct hssp_data *d); +unsigned char VerifySwRevision(struct hssp_data *d); +void ExitProgrammingMode(void); +unsigned char ReadHsspErrorStatus(void); +unsigned char ReadSromStatus(void); + +#endif /* __PROGRAMMINGSTEPS_H */ + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/SWD_PacketLayer.c b/drivers/misc/cypress/SWD_PacketLayer.c new file mode 100644 index 000000000000..07459ac3dd0f --- /dev/null +++ b/drivers/misc/cypress/SWD_PacketLayer.c @@ -0,0 +1,621 @@ +/****************************************************************************** +* File Name: SWD_PacketLayer.c +* Version 1.0 +* +* Description: +* This file provides the source code for the packet layer functions of the +* SWD protocol. This includes SWD Read packet, SWD Write packet. +* +* Owner: +* Tushar Rastogi, Application Engineer (tusr@cypress.com) +* +* Related Document: +* AN84858 - PSoC 4 Programming using an External Microcontroller (HSSP) +* +* Hardware Dependency: +* PSoC 5LP Development Kit - CY8CKIT-050 +* +* Code Tested With: +* PSoC Creator 2.2 +* ARM GCC 4.4.1 +* CY8CKIT-050 +* +* Note: +* The functions in SWD packet layer use the bit banging macros, functions +* in "SWD_PhysicalLayer.h" +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ + +/****************************************************************************** +* Header file Inclusion +******************************************************************************/ +#include "SWD_PacketLayer.h" + +/* "SWD_PhysicalLayer.h" file contains the bit banging routines for + programming */ +#include "SWD_PhysicalLayer.h" + +/****************************************************************************** +* Global Variable definitions +******************************************************************************/ +/* Stores the 8-bit SWD Packet header */ +unsigned char swd_PacketHeader; + +/* Stores the 3-bit SWD Packet ACK data */ +unsigned char swd_PacketAck; + +/* 4-byte Read, Write packet data */ +unsigned char swd_PacketData[DATA_BYTES_PER_PACKET]; + +/****************************************************************************** +* Function Definitions +******************************************************************************/ + +/****************************************************************************** +* Function Name: Swd_SendByte +******************************************************************************* +* +* Summary: +* Sends a byte of data on the SWD lines (SWDIO, SWDCK) +* +* Parameters: +* txByte: Data byte to be sent by host on SWDIO line (Least significant bit +* sent first) +* +* Return: +* None. +* +* Note: +* This function is called for sending SWD header data in SWD Read/Write +* packets, and also to send data in a SWD Write packet. +* +******************************************************************************/ +static void Swd_SendByte(unsigned char txByte) +{ + unsigned char loop = 0; + + /* Loop for 8-bits of a byte */ + for (loop = 0; loop < 8; loop++) { + if (txByte & LSB_BIT_MASK) { /* Send a '1' */ + SetSwdckLow(); + SetSwdioHigh(); + SetSwdckHigh(); + } else { /* Send a '0' */ + + SetSwdckLow(); + SetSwdioLow(); + SetSwdckHigh(); + } + + txByte = txByte >> 1; /* Make the next bit to send as LS bit */ + } +} + +/****************************************************************************** +* Function Name: Swd_ReceiveByte +******************************************************************************* +* +* Summary: +* Receives a byte of data on the SWD lines (SWDIO, SWDCK) +* +* Parameters: +* None. +* +* Return: +* rxByte: Data byte received by host on SWDIO line (Least significant bit is +* first received bit) +* +* Note: +* This function is called for reading data bytes in a SWD Read Packet +* +******************************************************************************/ +static unsigned char Swd_ReceiveByte(void) +{ + unsigned char loop = 0; + unsigned char rxBit = 0; + unsigned char rxByte = 0; + + /* Loop for 8-bits of a byte */ + for (loop = 0; loop < 8; loop++) { + SWDCK_OUTPUT_LOW; + + /* Read the SWDIO input line */ + rxBit = ReadSwdio(); + + SWDCK_OUTPUT_HIGH; + + rxByte = rxByte >> 1; + + if (rxBit) { /* Received a '1' */ + rxByte = rxByte | MSB_BIT_MASK; + } else { /* Received a '0' */ + + rxByte = rxByte & (~MSB_BIT_MASK); + } + + } + + return rxByte; +} + +/****************************************************************************** +* Function Name: Swd_FirstTurnAroundPhase +******************************************************************************* +* +* Summary: +* Generates one SWDCK clock cycle for Turnaround phase of a SWD packet. +* SWDIO drive mode is changed to High-Z drive mode so that the host can read +* the data on the SWDIO. +* +* Parameters: +* None. +* +* Return: +* None. +* +* Note: +* This function is called during SWD Read/Write packets +* +******************************************************************************/ +static void Swd_FirstTurnAroundPhase(void) +{ + /* Change to High-Z drive mode for host to read the SWDIO line */ + SetSwdioHizInput(); + SetSwdckLow(); + SetSwdckHigh(); +} + +/****************************************************************************** +* Function Name: Swd_SecondTurnAroundPhase +******************************************************************************* +* +* Summary: +* Generates one SWDCK clock cycle for Turnaround phase of a SWD packet. +* SWDIO drive mode is changed to CMOS output drive mode so that the host can +* write data on SWDIO. +* +* Parameters: +* None. +* +* Return: +* None. +* +* Note: +* This function is called during SWD Read/Write packets +* +******************************************************************************/ +static void Swd_SecondTurnAroundPhase(void) +{ + /* Change to CMOS output drive mode for host to write to SWDIO */ + SetSwdioCmosOutput(); + SetSwdckLow(); + SetSwdckHigh(); +} + +/****************************************************************************** +* Function Name: Swd_GetAckSegment +******************************************************************************** +* +* Summary: +* Gets the 3-bit ACK response in a SWD packet +* +* Parameters: +* None. +* +* Return: +* ack: +* 3-bit ACK response is returned as a byte. Three possible return values are: +* 0x01 - SWD_OK_ACK +* 0x02 - SWD_WAIT_ACK +* 0x04 - SWD_FAULT_ACK +* Any other return value - Undefined ACK code. +* Treat it similar to SWD_FAULT_ACK and abort operation. +* +* Note: +* This function is called during SWD Read/Write packets +* +******************************************************************************/ +static unsigned char Swd_GetAckSegment(void) +{ + unsigned char ack = 0; + unsigned char receiveBit = 0; + unsigned char loop = 0; + + /* ACK bits are received lsb bit first */ + for (loop = 0; loop < NUMBER_OF_ACK_BITS; loop++) { + SetSwdckLow(); + + /* Store the ACK bit received */ + receiveBit = ReadSwdio(); + SetSwdckHigh(); + + /* Concatenate the ACK bit with ACK data byte */ + ack = ack | (receiveBit << loop); + } + + return ack; +} + +/****************************************************************************** +* Function Name: Swd_SendParity +******************************************************************************* +* +* Summary: +* Sends the 1-bit parity data on SWD lines +* +* Parameters: +* parity: +* 1-bit parity data received as a byte (either '1' or '0') +* +* Return: +* None. +* +* Note: +* This function is called during SWD Write packet +* +******************************************************************************/ +static void Swd_SendParity(unsigned char parity) +{ + /* Make the clock low, Send SWDIO data, Make Clock high */ + + SetSwdckLow(); + if (parity) + SetSwdioHigh(); + else + SetSwdioLow(); + + SetSwdckHigh(); +} + +/****************************************************************************** +* Function Name: Swd_ReceiveParity +******************************************************************************* +* +* Summary: +* Receives the 1-bit parity data on SWD lines +* +* Parameters: +* None. +* +* Return: +* parity: +* 1-bit parity data returned as a byte (either '1' or '0') +* +* Note: +* This function is called during SWD Read packet +* +******************************************************************************/ +static unsigned char Swd_ReceiveParity(void) +{ + unsigned char parity; + + /* Make the clock low, Read SWDIO data, Make Clock high */ + + SetSwdckLow(); + parity = ReadSwdio(); + SetSwdckHigh(); + + return parity; +} + +/****************************************************************************** +* Function Name: Swd_SendDummyClocks +******************************************************************************* +* +* Summary: +* Sends three SWDCK clock cycles with SWDIO line held low +* +* Parameters: +* None. +* +* Return: +* None. +* +* Note: +* This function is called during SWD Read/Write packets. +* +******************************************************************************/ +void Swd_SendDummyClocks(void) +{ + unsigned char loop; + + /* Send three SWDCK clock cycles with SWDIO line held low */ + SetSwdioLow(); + for (loop = 0; loop < NUMBER_OF_DUMMY_SWD_CLOCK_CYCLES; loop++) { + SetSwdckLow(); + SetSwdckHigh(); + } +} + +/****************************************************************************** +* Function Name: Swd_CountOneBits +******************************************************************************* +* +* Summary: +* Counts the number of 1's in a byte +* +* Parameters: +* dataByte: +* Byte for which the number of 1's need to be found +* +* Return: +* count: +* Number of 1's present in DataByte +* +* Note: +* This function is used for computing parity of data +* +******************************************************************************/ +static unsigned char Swd_CountOneBits(unsigned char dataByte) +{ + unsigned char count = 0; + unsigned char i; + + /* Loop for 8-bits of a byte */ + /* Increment count variable if LS bit is set */ + for (i = 0; i < 8; i++) { + if (dataByte & LSB_BIT_MASK) + count++; + + dataByte = dataByte >> 1; + } + + return count; +} + +/****************************************************************************** +* Function Name: Swd_ComputeDataParity +******************************************************************************* +* +* Summary: +* Computes Even parity of 4-byte data +* +* Parameters: +* swd_PacketData[DATA_BYTES_PER_PACKET] - Global variable that holds the data +* +* Return: +* Even parity bit +* 0x01 - Parity is '1' if 4-byte data has an odd number of 1's +* 0x00 - Parity is '0' if 4-byte data has an even number of 1's +* +* Note: +* This function is called during SWD Read/Write packets +* +******************************************************************************/ +static unsigned char Swd_ComputeDataParity(void) +{ + unsigned char count = 0; + unsigned char i; + + /* Count number of 1's in 4-byte data */ + for (i = 0; i < DATA_BYTES_PER_PACKET; i++) + count = count + Swd_CountOneBits(swd_PacketData[i]); + + /* Return even parity. If Lsb bit is 1, it implies the number of 1's + is odd, and hence the even parity bit is set. For even number + of 1's, parity bit is 0 */ + return count & LSB_BIT_MASK; +} + +/****************************************************************************** +* Function Name: Swd_ReadPacket +******************************************************************************* +* +* Summary: +* Sends a single SWD Read packet +* +* Parameters: +* swd_PacketHeader - Global variable that holds the 8-bit header data for packet +* +* Return: +* swd_PacketData[DATA_BYTES_PER_PACKET] - Global variable that holds the 4-byte +* data that has been read +* +* swd_PacketAck - Global variable that holds the status of the SWD transaction +* ACK response is stored as a byte. Three possible ACK return values are: +* 0x01 - SWD_OK_ACK +* 0x02 - SWD_WAIT_ACK +* 0x04 - SWD_FAULT_ACK +* 0x09 - SWD_OK_ACK, but Parity error in data received +* Any other ACK value - Undefined ACK code. +* Treat it similar to SWD_FAULT_ACK and abort +* operation. +* +* Note: +* 1.)Swd_RawReadPacket() is called during SPC Polling operations when the host +* must read the SPC status register continuously till a Programming +* operation is completed or data is ready to be read. +* +* 2.)This function is called duing continuous multi byte read operations from +* the SPC_DATA register +* +* 3.)This function is called during IDCODE instruction for reading the Device +* JTAG ID +* +* 4.)This function is not called during normal SWD read transactions. To read +* a register data, two SWD Read packets must be sent (call this function +* twice). This method of reading twice has been implemented in +* SWD_ReadPacket() function which will be called during normal read +* transactions. +* +******************************************************************************/ +void Swd_ReadPacket(void) +{ + unsigned char parity; + unsigned char loop = 0; + unsigned char i; + + do { + /* 8-bit Header data */ + Swd_SendByte(swd_PacketHeader); + + /* First Turnaround phase */ + Swd_FirstTurnAroundPhase(); + + /* Get the 3-bit ACK data */ + swd_PacketAck = Swd_GetAckSegment(); + + /* Read 4-byte data and store in Global + array swd_PacketData[] */ + for (i = 0; i < DATA_BYTES_PER_PACKET; i++) + swd_PacketData[i] = Swd_ReceiveByte(); + + /* Parity phase */ + parity = Swd_ReceiveParity(); + + /* Second Turnaround phase */ + Swd_SecondTurnAroundPhase(); + + /* Dummy clock phase since clock is not free running */ + Swd_SendDummyClocks(); + + /* Repeat for a WAIT ACK till timeout loop expires */ + loop++; + + } while ((swd_PacketAck == SWD_WAIT_ACK) + && (loop < NUMBER_OF_WAIT_ACK_LOOPS)); + + /* For a OK ACK, check the parity bit received with parity computed */ + if (swd_PacketAck == SWD_OK_ACK) { + if (parity != Swd_ComputeDataParity()) { + /* Set the Parity error bit in ACK code */ + swd_PacketAck = swd_PacketAck | SWD_PARITY_ERROR; + } + } + + /* Swd_PacketAck global variable holds the status of + the SWD transaction */ +} + +/****************************************************************************** +* Function Name: Swd_WritePacket +******************************************************************************* +* +* Summary: +* Sends a single SWD Write packet +* +* Parameters: +* swd_PacketHeader - Global variable that holds the 8-bit header data +* for packet +* swd_PacketData[DATA_BYTES_PER_PACKET] - Global variable that holds the data +* to be sent +* +* Return: +* swd_PacketAck - Global variable that holds the status of the SWD transaction +* ACK response is stored as a byte. Three possible ACK return values are: +* 0x01 - SWD_OK_ACK +* 0x02 - SWD_WAIT_ACK +* 0x04 - SWD_FAULT_ACK +* Any other ACK value - Undefined ACK code. +* Treat it similar to SWD_FAULT_ACK and abort operation. +* +* Note: +* This function is called for Address Write, Data Write operations +* +******************************************************************************/ +void Swd_WritePacket(void) +{ + unsigned char parity; + unsigned char loop = 0; + unsigned char i; + + /* Compute Even parity for 4-byte data */ + parity = Swd_ComputeDataParity(); + + do { + /* 8-bit Header data */ + Swd_SendByte(swd_PacketHeader); + + /* First Turnaround phase */ + Swd_FirstTurnAroundPhase(); + + /* Get the 3-bit ACK data */ + swd_PacketAck = Swd_GetAckSegment(); + + /* Second Turnaround phase */ + Swd_SecondTurnAroundPhase(); + + /* Send 4-byte data stored in Global array swd_PacketData[] */ + for (i = 0; i < DATA_BYTES_PER_PACKET; i++) + Swd_SendByte(swd_PacketData[i]); + + /* Parity phase */ + Swd_SendParity(parity); + + /* Dummy clock phase since clock is not free running */ + Swd_SendDummyClocks(); + + loop++; + + /* Repeat for a WAIT ACK till timeout loop expires */ + + } while ((swd_PacketAck == SWD_WAIT_ACK) + && (loop < NUMBER_OF_WAIT_ACK_LOOPS)); + + /* swd_PacketAck global variable holds the status of + the SWD transaction */ +} + +/****************************************************************************** +* Function Name: Swd_LineReset +******************************************************************************* +* +* Summary: +* Resets the SWD line by sending 51 SWDCK clock cycles with SWDIO line high +* +* Parameters: +* None +* +* Return: +* None +* +* Note: +* This function is called as part of SWD switching sequence +* +******************************************************************************/ +void Swd_LineReset(void) +{ + unsigned char i; + + /* To reset SWD line, clock more than 50 SWDCK clock cycles with SWDIO + high. */ + + SWDIO_OUTPUT_HIGH; + + for (i = 0; i < NUMBER_OF_SWD_RESET_CLOCK_CYCLES; i++) { + SWDCK_OUTPUT_LOW; + SWDCK_OUTPUT_HIGH; + } + SWDCK_OUTPUT_LOW; + SWDIO_OUTPUT_LOW; + SWDCK_OUTPUT_HIGH; +} + +/* []END OF FILE */ diff --git a/drivers/misc/cypress/SWD_PacketLayer.h b/drivers/misc/cypress/SWD_PacketLayer.h new file mode 100644 index 000000000000..7add4123bcf5 --- /dev/null +++ b/drivers/misc/cypress/SWD_PacketLayer.h @@ -0,0 +1,100 @@ +/****************************************************************************** +* File Name: SWD_PacketLayer.h +* Version 1.0 +* +* Description: +* This header file contains the constant definitions, function declarations +* associated with the packet layer of the SWD protocol. +* +* Note: +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ + +#ifndef __SWD_PACKETLAYER_H +#define __SWD_PACKETLAYER_H + +/****************************************************************************** +* Constant definitions +******************************************************************************/ + +/* Data size of a SWD Packet in bytes */ +#define DATA_BYTES_PER_PACKET 4 + +/* Number of dummy SWDCK clocks at end of each SWD packet. + Required for bit banging programmers where clock is not free running */ +#define NUMBER_OF_DUMMY_SWD_CLOCK_CYCLES 3 + +/* Minimum number of SWDCK clock cycles to reset the SWD line state */ +#define NUMBER_OF_SWD_RESET_CLOCK_CYCLES 51 + +/* ACK response in a SWD packet is a 3-bit value */ +#define NUMBER_OF_ACK_BITS 3 + +/* SWD ACK response meanings. +* Parity error definition is not part of SWD ACK response from target PSoC 4. +* The actual ACK response is only 3-bit length. The parity error bit is +* defined as fourth bit by host application. It is generated by host if there +* is a parity error in the SWD Read packet data from target PSoC 4 */ +#define SWD_OK_ACK 0x01 +#define SWD_WAIT_ACK 0x02 +#define SWD_FAULT_ACK 0x04 +#define SWD_PARITY_ERROR 0x08 + +/* Maximum SWD packet loop timeout for SWD_WAIT_ACK response */ +#define NUMBER_OF_WAIT_ACK_LOOPS 5 + +/* Mask value to define Most significant bit (MSb) in a Byte */ +#define MSB_BIT_MASK 0x80 +/* Mask value to define Least significant bit (LSb) in a Byte */ +#define LSB_BIT_MASK 0x01 + +/****************************************************************************** +* Global Variable declaration +******************************************************************************/ +/* The below global variables are accessed by the upper layer files to create + SWD packet header, ACK, data */ + +extern unsigned char swd_PacketHeader; +extern unsigned char swd_PacketAck; +extern unsigned char swd_PacketData[DATA_BYTES_PER_PACKET]; + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ +/* The below public fuctions are called by the upper layer files to send SWD + packets */ +void Swd_WritePacket(void); +void Swd_ReadPacket(void); +void Swd_LineReset(void); +void Swd_SendDummyClocks(void); + +#endif /* __SWD_PACKETLAYER_H */ + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/SWD_PhysicalLayer.h b/drivers/misc/cypress/SWD_PhysicalLayer.h new file mode 100644 index 000000000000..5f4e655f43f7 --- /dev/null +++ b/drivers/misc/cypress/SWD_PhysicalLayer.h @@ -0,0 +1,180 @@ +/****************************************************************************** + * File Name: SWD_PhysicalLayer.h + * Version 1.0 + * + * Description: + * This header file contains the macro definitions, function declarations for + * the physical layer of the SWD protocol. These include - + * a.) Setting a output pin high or low + * b.) Reading the logic level of an input pin + * c.) Configuring the drive mode of the programming pin + * + * The pin manipulation routines are defined both as macros and functions. + * The macros are used in "Step 1. DeviceAcquire()" as the function has strict + * timing requirements for execution. Using the macros instead of fuctions + * reduces execution overhead. + * + * The pin manipulation functions are used instead of macros in all other + * places to save code space. + * + * Note: + * The macros, functions defined here are specific to PSoC 5LP Host Programmer. + * Modify them as applicable for your Host Programmer. + * + ******************************************************************************* + * Copyright (2013), Cypress Semiconductor Corporation. + ******************************************************************************* + * This software is owned by Cypress Semiconductor Corporation (Cypress) and is + * protected by and subject to worldwide patent protection (United States and + * foreign), United States copyright laws and international treaty provisions. + * Cypress hereby grants to licensee a personal, non-exclusive, non-transferable + * license to copy, use, modify, create derivative works of, and compile the + * Cypress Source Code and derivative works for the sole purpose of creating + * custom software in support of licensee product to be used only in conjunction + * with a Cypress integrated circuit as specified in the applicable agreement. + * Any reproduction, modification, translation, compilation, or representation of + * this software except as specified above is prohibited without the express + * written permission of Cypress. + * + * Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH + * REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Cypress reserves the right to make changes without further notice to the + * materials described herein. Cypress does not assume any liability arising out + * of the application or use of any product or circuit described herein. Cypress + * does not authorize its products for use as critical components in life-support + * systems where a malfunction or failure may reasonably be expected to result in + * significant injury to the user. The inclusion of Cypress' product in a life- + * support systems application implies that the manufacturer assumes all risk of + * such use and in doing so indemnifies Cypress against all charges. Use may be + * limited by and subject to the applicable Cypress software license agreement. + ******************************************************************************/ + +#ifndef __SWD_PHYSICALLAYER_H +#define __SWD_PHYSICALLAYER_H + +/* Host programmer registers, mask values are defined in "RegisterDefines.h" */ + +#include +#include +#include +#include "cycapsense_hssp.h" + +extern struct cycapsense_ctrl_data *ctrl_data; + +#define HSSP_CLK (ctrl_data->hssp_d.c_gpio) +#define HSSP_DAT (ctrl_data->hssp_d.d_gpio) +#define HSSP_RST (ctrl_data->hssp_d.rst_gpio) +#define HSSP_CLK_OFF (ctrl_data->hssp_d.c_offset) +#define HSSP_DAT_OFF (ctrl_data->hssp_d.d_offset) +#define HSSP_CLK_GROUP_OFF (ctrl_data->hssp_d.c_group_offset) +#define HSSP_DAT_GROUP_OFF (ctrl_data->hssp_d.d_group_offset) +#define MSM_TLMM_BASE (ctrl_data->hssp_d.gpio_base) + +#define GPIO_IN_OUT(n) (MSM_TLMM_BASE + (0x1000 * n)) + +static inline void hssp_set_clk_gpio(int gpio, int offset, int value) +{ + if (ctrl_data->hssp_d.raw_mode) { + writel_relaxed_no_log(value ? 2 : 0, (GPIO_IN_OUT(offset) + HSSP_CLK_GROUP_OFF)); + } else + gpio_set_value(gpio, value); +} +static inline void hssp_set_dat_gpio(int gpio, int offset, int value) +{ + if (ctrl_data->hssp_d.raw_mode) { + writel_relaxed_no_log(value ? 2 : 0, (GPIO_IN_OUT(offset) + HSSP_DAT_GROUP_OFF)); + } else + gpio_set_value(gpio, value); +} + + +static inline int hssp_get_gpio(int gpio, int offset) +{ + if (ctrl_data->hssp_d.raw_mode) + return !!(readl_relaxed_no_log((GPIO_IN_OUT(offset) + HSSP_DAT_GROUP_OFF)) & 0x1); + else + return gpio_get_value(gpio); +} + +/***************************** USER ATTENTION REQUIRED ************************ + ***************************** HOST PROCESSOR SPECIFIC ************************* + **************** Macros for Host Pin Drive mode configuration ***************** + * + * Uses the register definitions, mask values in "RegisterDefines.h" to + * configure the pin drive mode + * + * SWDIO pin on host side - CMOS output (host writes data to target PSoC 4), + * High Z digital input (host reads data from target + * PSoC 4 or when host is not programming target + * PSoC 4 (idle)) + * + * SWDCK pin on host side - CMOS output (when host is programming target PSoC 4), + * High Z digital input (when host is not programming + * target PSoC 4 (idle)) + * + * XRES pin on host side - CMOS output (when host is programming target PSoC 4) + * High Z digital input (when host is not programming + * target PSoC 4 (idle)) + * + * Modify these as applicable to your Host Programmer + ******************************************************************************/ + +#define SWDIO_DRIVEMODE_HIGHZIN SetSwdioHizInput() +#define SWDIO_DRIVEMODE_CMOSOUT SetSwdioCmosOutput() + +#define SWDCK_DRIVEMODE_HIGHZIN SetSwdckHizInput() +#define SWDCK_DRIVEMODE_CMOSOUT SetSwdckCmosOutput() + +#define XRES_DRIVEMODE_CMOSOUT SetXresCmosOutput() +#define XRES_DRIVEMODE_HIGHZIN SetXresHizInput() + +/***************************** USER ATTENTION REQUIRED ************************ + ***************************** HOST PROCESSOR SPECIFIC ************************* + **************** Macros for driving output pins on host side ****************** + * + * Uses the register definitions, mask values in "RegisterDefines.h" to drive + * output pins either to logic high (suffixed by 'HIGH') or + * logic low (suffixed by 'LOW') + * + * Modify these as applicable to your Host Programmer + ******************************************************************************/ + +#define SWDIO_OUTPUT_HIGH SetSwdioHigh() +#define SWDIO_OUTPUT_LOW SetSwdioLow() + +#define SWDCK_OUTPUT_HIGH SetSwdckHigh() +#define SWDCK_OUTPUT_LOW SetSwdckLow() + +#define XRES_OUTPUT_HIGH SetXresHigh() +#define XRES_OUTPUT_LOW SetXresLow() + +/****************************************************************************** + * Function Prototypes + ******************************************************************************/ +/* The below fuctions are for pin manipulation, and their definitions in + * SWD_PhysicalLayer.c are the same as the corresponding macro defitnions + * above. */ + +#define SetSwdckHigh() hssp_set_clk_gpio(HSSP_CLK, HSSP_CLK_OFF, 1) +#define SetSwdckLow() hssp_set_clk_gpio(HSSP_CLK, HSSP_CLK_OFF, 0) + +#define SetSwdckCmosOutput() gpio_direction_output(HSSP_CLK, 0) +#define SetSwdckHizInput() gpio_direction_input(HSSP_CLK) + +#define SetSwdioHigh() hssp_set_dat_gpio(HSSP_DAT, HSSP_DAT_OFF, 1) +#define SetSwdioLow() hssp_set_dat_gpio(HSSP_DAT, HSSP_DAT_OFF, 0) + +#define SetSwdioCmosOutput() gpio_direction_output(HSSP_DAT, 0) +#define ReadSwdio() hssp_get_gpio(HSSP_DAT, HSSP_DAT_OFF) + +#define SetSwdioHizInput() gpio_direction_input(HSSP_DAT) + +#define SetXresHigh() gpio_set_value(HSSP_RST, 1) +#define SetXresLow() gpio_set_value(HSSP_RST, 0) +#define SetXresCmosOutput() gpio_direction_output(HSSP_RST, 0) +#define SetXresHizInput() gpio_direction_input(HSSP_RST) + +#endif /* __SWD_PHYSICALLAYER_H */ + +/*[] END OF FILE */ diff --git a/drivers/misc/cypress/SWD_UpperPacketLayer.c b/drivers/misc/cypress/SWD_UpperPacketLayer.c new file mode 100644 index 000000000000..28dd4b9d0ca8 --- /dev/null +++ b/drivers/misc/cypress/SWD_UpperPacketLayer.c @@ -0,0 +1,182 @@ +/****************************************************************************** +* File Name: Swd_UpperPacketLayer.c +* Version 1.0 +* +* Description: +* This file provides the source code for function associated with the upper +* packet layer of the SWD protocol. +* +* Owner: +* Tushar Rastogi, Application Engineer (tusr@cypress.com) +* +* Related Document: +* AN84858 - PSoC 4 Programming using an External Microcontroller (HSSP) +* +* Hardware Dependency: +* PSoC 5LP Development Kit - CY8CKIT-050 +* +* Code Tested With: +* PSoC Creator 2.2 +* ARM GCC 4.4.1 +* CY8CKIT-050 +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. + +******************************************************************************/ + +/****************************************************************************** +* Header file Inclusion +******************************************************************************/ +#include "SWD_PacketLayer.h" +#include "SWD_UpperPacketLayer.h" + +/****************************************************************************** +* Function Definitions +******************************************************************************/ + +/****************************************************************************** +* Function Name: Read_DAP +******************************************************************************* +* +* Summary: +* Reads the Swd_DAP_Register and stores the returned 32 bit value +* +* Parameters: +* swd_DAP_Register - MACROS for reading Debug Port and Access Port Register +* data_32 - 32-bit variable containing the returned value +* +* Return: +* None +* +******************************************************************************/ +void Read_DAP(unsigned char swd_DAP_Register, unsigned long *data_32) +{ + swd_PacketHeader = swd_DAP_Register; + + Swd_ReadPacket(); + if (swd_PacketAck != SWD_OK_ACK) + return; + + *data_32 = + (((unsigned long)swd_PacketData[3] << 24) | + ((unsigned long)swd_PacketData[2] << 16) | ((unsigned long) + swd_PacketData[1] << 8) + | ((unsigned long)swd_PacketData[0])); +} + +/****************************************************************************** +* Function Name: Write_DAP +******************************************************************************* +* +* Summary: +* Writes a 32-bit value to swd_DAP_Register +* +* Parameters: +* swd_DAP_Register - MACROS for writing to Debug Port and Access Port Register +* data_32 - 32-bit variable containing the value to be written +* +* Return: +* None +* +******************************************************************************/ +void Write_DAP(unsigned char swd_DAP_Register, unsigned long data_32) +{ + swd_PacketHeader = swd_DAP_Register; + + swd_PacketData[3] = (unsigned char)(data_32 >> 24); + swd_PacketData[2] = (unsigned char)(data_32 >> 16); + swd_PacketData[1] = (unsigned char)(data_32 >> 8); + swd_PacketData[0] = (unsigned char)(data_32); + + Swd_WritePacket(); +} + +/****************************************************************************** +* Function Name: Read_IO +******************************************************************************* +* +* Summary: +* Reads 32-bit date from specified address of CPU address space. +* Returns OK ACK if all SWD transactions succeeds (ACKed). +* +* Parameters: +* addr_32 - Address from which the data has to be read from CPU address space +* data_32 - 32-bit variable containing the read value +* +* Return: +* Swd_PacketAck - Acknowledge packet for the last SWD transaction +* +*******************************************************************************/ +unsigned char Read_IO(unsigned long addr_32, unsigned long *data_32) +{ + Write_DAP(DPACC_AP_TAR_WRITE, addr_32); + if (swd_PacketAck != SWD_OK_ACK) + return swd_PacketAck; + + Read_DAP(DPACC_AP_DRW_READ, data_32); + if (swd_PacketAck != SWD_OK_ACK) + return swd_PacketAck; + + Read_DAP(DPACC_AP_DRW_READ, data_32); + if (swd_PacketAck != SWD_OK_ACK) + return swd_PacketAck; + + return swd_PacketAck; +} + +/****************************************************************************** +* Function Name: Write_IO +******************************************************************************* +* +* Summary: +* Writes 32-bit data into specified address of CPU address space. +* Returns “true” if all SWD transactions succeeded (ACKed). +* +* Parameters: +* addr_32 - Address at which the data has to be written in CPU address space +* data_32 - 32-bit variable containing the value to be written +* +* Return: +* swd_PacketAck - Acknowledge packet for the last SWD transaction +* +******************************************************************************/ +unsigned char Write_IO(unsigned long addr_32, unsigned long data_32) +{ + Write_DAP(DPACC_AP_TAR_WRITE, addr_32); + if (swd_PacketAck != SWD_OK_ACK) + return swd_PacketAck; + + Write_DAP(DPACC_AP_DRW_WRITE, data_32); + if (swd_PacketAck != SWD_OK_ACK) + return swd_PacketAck; + + return swd_PacketAck; +} + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/SWD_UpperPacketLayer.h b/drivers/misc/cypress/SWD_UpperPacketLayer.h new file mode 100644 index 000000000000..2383c9e62cd9 --- /dev/null +++ b/drivers/misc/cypress/SWD_UpperPacketLayer.h @@ -0,0 +1,72 @@ +/****************************************************************************** +* File Name: SWD_UpperPacketLayer.h +* Version 1.0 +* +* Description: +* This header file contains the constant definitions, function declarations +* associated with the upper packet layer of the SWD protocol. +* +* Note: +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ + +#ifndef __SWD_UPPERPACKETLAYER_H +#define __SWD_UPPERPACKETLAYER_H + +/****************************************************************************** +* Constant definitions +******************************************************************************/ + +/* Macro Definitions for Debug and Access Port registers read and write Commands + used in the functions defined in UpperPacketLayer.c */ +#define DPACC_DP_CTRLSTAT_READ 0x8D +#define DPACC_DP_IDCODE_READ 0xA5 +#define DPACC_AP_CSW_READ 0x87 +#define DPACC_AP_TAR_READ 0xAF +#define DPACC_AP_DRW_READ 0x9F + +#define DPACC_DP_ABORT_WRITE 0x81 +#define DPACC_DP_CTRLSTAT_WRITE 0xA9 +#define DPACC_DP_SELECT_WRITE 0xB1 +#define DPACC_AP_CSW_WRITE 0xA3 +#define DPACC_AP_TAR_WRITE 0x8B +#define DPACC_AP_DRW_WRITE 0xBB + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ +void Read_DAP(unsigned char swd_DAP_Register, unsigned long *data_32); +void Write_DAP(unsigned char swd_DAP_Register, unsigned long data_32); +unsigned char Read_IO(unsigned long addr_32, unsigned long *data_32); +unsigned char Write_IO(unsigned long addr_32, unsigned long data_32); + +#endif /* __SWD_UPPERPACKETLAYER_H */ + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/Timeout.h b/drivers/misc/cypress/Timeout.h new file mode 100644 index 000000000000..dbdef4ecc432 --- /dev/null +++ b/drivers/misc/cypress/Timeout.h @@ -0,0 +1,81 @@ +/****************************************************************************** +* File Name: Timeout.h +* Version 1.0 +* +* Description: +* This header file contains the definitions for timeout parameters, function +* declaration for the delay routine. These definitions will vary based on host +* processor used to program target PSoC 5LP. Change the timeout values based on +* your Host processor. +* +* Note: +* Refer to the TimeoutCalc.h header file in the other project +* "C_Hssp_TimeoutCalc" for details on the procedure to calculate these +* parameters for your specific host programmer. +* +******************************************************************************* +* Copyright (2013), Cypress Semiconductor Corporation. +******************************************************************************* +* This software is owned by Cypress Semiconductor Corporation (Cypress) and is +* protected by and subject to worldwide patent protection (United States and +* foreign), United States copyright laws and international treaty provisions. +* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable +* license to copy, use, modify, create derivative works of, and compile the +* Cypress Source Code and derivative works for the sole purpose of creating +* custom software in support of licensee product to be used only in conjunction +* with a Cypress integrated circuit as specified in the applicable agreement. +* Any reproduction, modification, translation, compilation, or representation of +* this software except as specified above is prohibited without the express +* written permission of Cypress. +* +* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH +* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* Cypress reserves the right to make changes without further notice to the +* materials described herein. Cypress does not assume any liability arising out +* of the application or use of any product or circuit described herein. Cypress +* does not authorize its products for use as critical components in life-support +* systems where a malfunction or failure may reasonably be expected to result in +* significant injury to the user. The inclusion of Cypress' product in a life- +* support systems application implies that the manufacturer assumes all risk of +* such use and in doing so indemnifies Cypress against all charges. Use may be +* limited by and subject to the applicable Cypress software license agreement. +******************************************************************************/ +#ifndef __TIMEOUT_H +#define __TIMEOUT_H + +/****************************************************************************** +* Macro definitions +******************************************************************************/ +#include + +/***************************** USER ATTENTION REQUIRED ************************ +***************************** HOST PROCESSOR SPECIFIC ************************* +* All below three timeout values namely: DEVICE_ACQUIRE_TIMEOUT, +* XRES_PULSE_100US, and SROM_POLLING_TIMEOUT are for a PSoC 5LP Host programmer +* running at 63 MHz. Modify these values as required for your host processor. +* Refer to the TimeoutCalc.h header file in the other project +* "C_Hssp_TimeoutCalc" for details on the procedure to calculate these +* parameters for your specific host programmer. +******************************************************************************/ + +#define XRES_PULSE_100US 600 +#if defined CY8C40xx_FAMILY +#define DEVICE_ACQUIRE_TIMEOUT 40 /* 40 retries, about 2 ms */ +#else +#define DEVICE_ACQUIRE_TIMEOUT 15 +#endif +#define SROM_POLLING_TIMEOUT 210416 + +/****************************************************************************** +* Function Prototypes +******************************************************************************/ + +static inline void DelayHundredUs(void) +{ + udelay(100); +} + +#endif /* __TIMEOUT_H */ + +/* [] END OF FILE */ diff --git a/drivers/misc/cypress/cycapsense_hssp.h b/drivers/misc/cypress/cycapsense_hssp.h new file mode 100644 index 000000000000..d20d8f3956c8 --- /dev/null +++ b/drivers/misc/cypress/cycapsense_hssp.h @@ -0,0 +1,80 @@ + +/* + * Header file for: + * Cypress CapSense(TM) firmware downloader. + * + * Copyright (c) 2015 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __CYCAPSENSE_HSSP_H__ +#define __CYCAPSENSE_HSSP_H__ + +#include +#include +#include + +struct hex_info { + char fw_name[NAME_MAX]; + u8 *data; + u8 *s_data; + u8 *m_data; + u8 cl_protection; + u16 cs; +}; +struct hssp_data { + struct hex_info inf; + const char *name; + unsigned int silicon_id; + int block_size; + int num_of_blocks; + int secure_bytes; + int c_gpio; + int d_gpio; + int rst_gpio; + int raw_mode; + int c_offset; + int d_offset; + u32 c_group_offset; + u32 d_group_offset; + void __iomem *gpio_base; + u16 chip_cs; + u16 sw_rev; +}; +struct cycapsense_ctrl_data { + struct device *dev; + struct hssp_data hssp_d; + struct work_struct work; + int cmd; +}; + +#define HSSP_CMD_NONE 0 +#define HSSP_CMD_RESET 1 +#define HSSP_CMD_ERASE 2 +#define HSSP_CMD_FW_UPDATE 3 + +int cycapsense_hssp_dnld(struct hssp_data *d); + +#define P4000_METADATA_SIZE 12 +#define SILICON_ID_BYTE_LENGTH 4 +#define FLASH_ROW_BYTE_SIZE_HEX_FILE 128 +#define NUMBER_OF_FLASH_ROWS_HEX_FILE 128 +#define SW_REVISION_OFFSET 0x3f7c + +#define FAILURE 1 +#define SUCCESS 0 + +#define RST_GPIO 1 +#define CLK_GPIO 4 +#define DAT_GPIO 7 + + +#endif /* __CYCAPSENSE_HSSP_H__ */ diff --git a/drivers/misc/cypress/cyttsp_sar.h b/drivers/misc/cypress/cyttsp_sar.h new file mode 100644 index 000000000000..2b932c76381d --- /dev/null +++ b/drivers/misc/cypress/cyttsp_sar.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 XiaoMi, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _CYTTSP_SAR_H_ +#define _CYTTSP_SAR_H_ + +#include + +#define CYTTSP_SAR_CHANNEL_ENABLE 0x06 +#define CYTTSP_SAR_FORCE_CALIBRATE 0x07 +#define CYTTSP_SAR_CHANNEL_MAX 0x08 +#define CYTTSP_SAR_STATE_ERROR 0x03 + +#define CYTTSP_CMD_VERIFY_CHKSUM 0x31 +#define CYTTSP_CMD_GET_FLASH_SIZE 0x32 +#define CYTTSP_CMD_ERASE_ROW 0x34 +#define CYTTSP_CMD_SEND_DATA 0x37 +#define CYTTSP_CMD_ENTER_BTLD 0x38 +#define CYTTSP_CMD_PROGRAM_ROW 0x39 +#define CYTTSP_CMD_VERIFY_ROW 0x3A +#define CYTTSP_CMD_EXIT_BTLD 0x3B + +#define CYTTSP_REG_TOUCHMODE 0x00 +#define CYTTSP_REG_HWVERSION 0x59 +#define CYTTSP_REG_INTERRUPT_PEDNING 0x50 +#define CYTTSP_REG_STATUS_LSB 0x51 +#define CYTTSP_REG_STATUS_MSB 0x52 + + +#define CYTTSP_REG_INVALID 0xFF + +#define CYTTSP_NORMAL_MODE 0x00 +#define CYTTSP_STANDBY_MODE 0x01 + +#define CYTTSP_STS_SUCCESS 0x00 + +#define CYTTSP_SAR_OP_MODE 0x00 +#define CYTTSP_SAR_FW_VER1 0x57 +#define CYTTSP_SAR_FW_VER2 0x58 + +#define CYTTSP_PACKET_START 0x01 +#define CYTTSP_PACKET_END 0x17 + +#define CYTTSP_MAX_PAYLOAD_LEN 0x15 + +#define CYTTSP_RESP_HEADER_LEN 0x4 +#define CYTTSP_RESP_TAIL_LEN 0x3 + +#define CYTTSP_ENTER_BTLD_RESP_LEN 8 +#define CYTTSP_GET_FLASHSZ_RESP_LEN 4 + + +#define CYTTSP_FW_VERSION_FILE_OFFSET 183 + + +/************************************** + * define platform data + * + **************************************/ +struct cyttsp_reg_data { + unsigned char reg; + unsigned char val; +}; + +static struct cyttsp_reg_data cyttsp_i2c_reg_setup[] = { + { + .reg = CYTTSP_NORMAL_MODE, + .val = 0x00, + }, + { + .reg = CYTTSP_SAR_CHANNEL_ENABLE, + .val = 0x0f, + }, + { + .reg = CYTTSP_SAR_FORCE_CALIBRATE, + .val = 0x3e, + }, +}; + +typedef struct cyttsp_sar_data *pcyttsp_data_t; +struct cyttsp_sar_data { + struct i2c_client *client; + struct cyttsp_sar_platform_data *pdata; + struct regulator *regulator_vdd; + struct regulator *regulator_avdd; + struct regulator *regulator_vddio; + struct input_dev *input_dev[4]; + bool dbgdump; + unsigned long sensorStatus; + bool enable; + u8 bootloader_addr; + u8 app_addr; +}; + + +struct cyttsp_sar_platform_data { + int irq_gpio; + u32 irq_gpio_flags; + unsigned long irqflags; + const char *input_name; + int i2c_reg_num; + struct cyttsp_reg_data *pi2c_reg; + int nsars; + int *key_code; + u8 sar_status_reg; + u8 bootloader_addr; + u8 standby_reg; + int default_config; + int config_array_size; + struct cyttsp_config_info *config_array; + bool cut_off_power; +}; + +#endif diff --git a/drivers/misc/cypress/cyttsp_sar_mmi.c b/drivers/misc/cypress/cyttsp_sar_mmi.c new file mode 100644 index 000000000000..6a95d8bf0247 --- /dev/null +++ b/drivers/misc/cypress/cyttsp_sar_mmi.c @@ -0,0 +1,1382 @@ +/* + * Copyright (C) 2013 Cypress, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cyttsp_sar.h" +#include +#include +#include +#include +#include +#include +#include "cycapsense_hssp.h" +#include "ProgrammingSteps.h" + +#define CYTTSP_DEBUG 1 +#define LOG_TAG "cyttsp " +#if CYTTSP_DEBUG +#define LOG_INFO(fmt, args...) pr_info(LOG_TAG fmt, ##args) +#else +#define LOG_INFO(fmt, args...) +#endif + +struct cycapsense_ctrl_data *ctrl_data; +static int programming_done; +static int fw_dl_status; +static BLOCKING_NOTIFIER_HEAD(hssp_notifier_list); + +pcyttsp_data_t pcyttsp_sar_ptr; +struct sensors_classdev sensors_capsensor_cdev[4]; + +static int cyttsp_i2c_read_block(struct device *dev, u8 addr, + u8 len, void *data) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_master_send(client, &addr, 1); + if (ret != 1) { + dev_err(dev, "Failed to read block!\n"); + return -EIO; + } + + ret = i2c_master_recv(client, data, len); + + return (ret < 0) ? ret : ret != len ? -EIO : 0; +} + +static u8 cyttsp_read_reg(struct cyttsp_sar_data *data, u8 reg) +{ + int ret; + u8 val; + + ret = cyttsp_i2c_read_block(&data->client->dev, + reg, 1, &val); + if (ret < 0) { + dev_err(&data->client->dev, "Failed to read reg!\n"); + return ret; + } + + return val; +} + +static int cyttsp_write_reg(struct cyttsp_sar_data *data, + u8 reg, u8 val) +{ + int ret; + u8 buffer[2]; + struct device *dev = &data->client->dev; + struct i2c_client *client = to_i2c_client(dev); + + buffer[0] = reg; + buffer[1] = val; + + ret = i2c_master_send(client, buffer, sizeof(buffer)); + if (ret != sizeof(buffer)) { + dev_err(&data->client->dev, "Failed to write reg!\n"); + return ret; + } + + return 0; +} + +static int cycapsense_validate_gpio(struct device *dev, + int gpio, char *name, int dir_out, int out_val) +{ + int error; + error = devm_gpio_request(dev, gpio, name); + if (error) { + dev_err(dev, "unable to request gpio [%d]\n", gpio); + goto f_end; + } + if (dir_out == 2) + goto f_end; + + if (dir_out == 1) + error = gpio_direction_output(gpio, out_val); + else + error = gpio_direction_input(gpio); + if (error) { + dev_err(dev, "unable to set direction for gpio [%d]\n", gpio); + goto f_end; + } +f_end: + return error; +} + +#ifdef CONFIG_OF +static void cyttsp_sar_dump_value(struct device *dev, + struct cyttsp_sar_platform_data *pdata) +{ + + dev_info(dev, "irq gpio = %d\n", pdata->irq_gpio); + dev_info(dev, "irqflags = %d\n", (int)pdata->irqflags); + dev_info(dev, "input name = %s\n", pdata->input_name); + dev_info(dev, "sar number = %d\n", pdata->nsars); + dev_info(dev, "sar_status_reg = 0x%x\n", pdata->sar_status_reg); + dev_info(dev, "standby_reg = 0x%x\n", pdata->standby_reg); + dev_info(dev, "default_config = %d\n", pdata->default_config); +} + +static int cyttsp_sar_parse_dt(struct device *dev, + struct cyttsp_sar_platform_data *pdata) +{ + int ret, error; + struct device_node *np = dev->of_node; + u32 temp_val; + unsigned int addr = 0, size = 0; + unsigned int gpios[12]; + + /* swd reset */ + dev_err(dev, "cycapsense_prog_probe reqeust reset gpio\n"); + ctrl_data->hssp_d.rst_gpio = of_get_gpio(np, 0); + error = cycapsense_validate_gpio(dev, + ctrl_data->hssp_d.rst_gpio, "capsense_reset_gpio", 1, 0); + if (error) + return error; + + gpio_export(ctrl_data->hssp_d.rst_gpio, false); + + dev_err(dev, "cycapsense_prog_probe clk gpio\n"); + ctrl_data->hssp_d.c_gpio = of_get_gpio(np, 1); + /*request only, direction == 2. Will be set by firmware loader*/ + error = cycapsense_validate_gpio(dev, + ctrl_data->hssp_d.c_gpio, "capsense_sclk_gpio", 2, 0); + if (error) + return error; + + dev_err(dev, "cycapsense_prog_probe data gpio\n"); + ctrl_data->hssp_d.d_gpio = of_get_gpio(np, 2); + /*request only, direction == 2. Will be set by firmware loader*/ + error = cycapsense_validate_gpio(dev, + ctrl_data->hssp_d.d_gpio, "capsense_sdata_gpio", 2, 0); + if (error) + return error; + + /*irq*/ + pdata->irq_gpio = of_get_gpio(np, 3); + + error = of_property_read_string(np, "label", &ctrl_data->hssp_d.name); + if (error) { + dev_err(dev, "Error reading node label\n"); + return error; + } + error = of_property_read_u32(np, "silicon_id", + &ctrl_data->hssp_d.silicon_id); + if (error) { + dev_err(dev, "Error reading node silicon id\n"); + return error; + } + error = of_property_read_u32(np, "block_size", + &ctrl_data->hssp_d.block_size); + if (error) { + dev_err(dev, "Error reading node block size\n"); + return error; + } + error = of_property_read_u32(np, "num_of_blocks", + &ctrl_data->hssp_d.num_of_blocks); + if (error) { + dev_err(dev, "Error reading node num_of_blocks\n"); + return error; + } + error = of_property_read_u32(np, "secure_bytes", + &ctrl_data->hssp_d.secure_bytes); + if (error) { + dev_err(dev, "Error reading node secure_bytes\n"); + return error; + } + of_property_read_u32(np, "use-raw-gpio-rw", + &ctrl_data->hssp_d.raw_mode); + if (ctrl_data->hssp_d.raw_mode) { + + of_property_read_u32(np, "gpio_base_addr", &addr); + of_property_read_u32(np, "gpio_base_size", &size); + memset(gpios, 0, sizeof(gpios)); + of_property_read_u32_array(np, "gpios", gpios, + ARRAY_SIZE(gpios)); + if (addr && size && gpios[CLK_GPIO] && gpios[DAT_GPIO]) { + ctrl_data->hssp_d.gpio_base = + devm_ioremap(dev, addr, size); + dev_info(dev, "gpio base addr = %p\n", ctrl_data->hssp_d.gpio_base); + ctrl_data->hssp_d.c_offset = gpios[CLK_GPIO]; + ctrl_data->hssp_d.d_offset = gpios[DAT_GPIO]; + dev_info(dev, "Raw GPIO (%d:%d) RW enabled\n", + ctrl_data->hssp_d.c_offset, + ctrl_data->hssp_d.d_offset); + error = of_property_read_u32(np, "gpio_clk_group", &ctrl_data->hssp_d.c_group_offset); + if (error) + ctrl_data->hssp_d.c_group_offset = 0x00; + error = of_property_read_u32(np, "gpio_dat_group", &ctrl_data->hssp_d.d_group_offset); + if (error) + ctrl_data->hssp_d.d_group_offset = 0x00; + dev_info(dev, "GPIO offset (0x%x, 0x%x) enabled\n", + ctrl_data->hssp_d.c_group_offset, + ctrl_data->hssp_d.d_group_offset); + } else { + ctrl_data->hssp_d.raw_mode = 0; + dev_info(dev, "Raw GPIO RW enabled but regs are not defined.Switch to normal mode\n"); + } + } + + + ret = of_property_read_u32(np, "cyttsp,sar-status-reg", + &temp_val); + if (ret) { + dev_err(dev, "Unable to read fw sar-status-reg\n"); + return ret; + } else + pdata->sar_status_reg = (u8)temp_val; + + pdata->cut_off_power = 0; + + ret = of_property_read_u32(np, "cyttsp,standby-reg", + &temp_val); + if (ret) { + dev_err(dev, "Unable to read standby reg\n"); + return ret; + } else + pdata->standby_reg = (u8)temp_val; + + ret = of_property_read_u32(np, "cyttsp,bootloader-addr", + &temp_val); + if (ret) + dev_err(dev, "Unable to read bootloader address\n"); + else + pdata->bootloader_addr = (u8)temp_val; + + ret = of_property_read_u32(np, "cyttsp,key-num", &temp_val); + if (ret) { + dev_err(dev, "Unable to read key num\n"); + return ret; + } else + pdata->nsars = temp_val; + + ret = of_property_read_u32(np, "cyttsp,default-config", + &pdata->default_config); + if (ret) { + dev_err(dev, "Unable to get default config\n"); + pdata->default_config = -1; + } + + cyttsp_sar_dump_value(dev, pdata); + + return 0; +} +#else +static int cyttsp_sar_parse_dt(struct device *dev, + struct cyttsp_sar_platform_data *pdata) +{ + return -ENODEV; +} +#endif + +static irqreturn_t cyttsp_sar_interrupt(int irq, void *dev_id) +{ + struct cyttsp_sar_data *data = dev_id; + struct cyttsp_sar_platform_data *pdata = data->pdata; + u8 temp[3]; + u32 sar_state = 0; + u32 sensor_status = 0; + int ret ; + int i; + u32 channel_status_mask[CYTTSP_SAR_CHANNEL_MAX] = { + 0x00000003, + 0x0000000C, + 0x00000030, + 0x000000C0, + 0x00000300, + 0x00000C00, + 0x00003000, + 0x0000C000 }; + + dev_info(&data->client->dev, "cypress irq handler!\n"); + + if (data->enable) { + ret = cyttsp_i2c_read_block(&data->client->dev, CYTTSP_REG_INTERRUPT_PEDNING, 3, &temp[0]); + if (ret < 0) { + dev_err(&data->client->dev, "Failed to read interrupt pending regsiter!\n"); + return IRQ_NONE; + } + + sensor_status = ((unsigned long)temp[1] + (unsigned long)(temp[2] << 8)); + for (i = 0; i < pdata->nsars; i++) { + + /* Report event only if sensor status for a specific channel has changed + and it matches the channel position in interrupt pending register */ + if (((sensor_status ^ data->sensorStatus) & channel_status_mask[i])) { + /* Find the sar state for the channel */ + sar_state = (sensor_status & channel_status_mask[i]) >> (i * 2); + + if (sar_state < CYTTSP_SAR_STATE_ERROR) { + input_report_abs(data->input_dev[i], ABS_DISTANCE, sar_state); + input_sync(data->input_dev[i]); + } else { + dev_err(&data->client->dev, "sar sensor error detected, Need reset!\n"); + } + } + } + + } + + data->sensorStatus = sensor_status; + + return IRQ_HANDLED; +} + +/** + * brief Initialize I2C config from platform data + * param this Pointer to main parent struct + * + */ +static void hw_init(void) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + + struct cyttsp_sar_platform_data *pdata = data->pdata; + int i = 0; + int ret; + /* configure device */ + LOG_INFO("Going to Setup I2C Registers\n"); + while (i < pdata->i2c_reg_num) { + /* Write all registers/values contained in i2c_reg */ + LOG_INFO("Going to Write Reg: 0x%x Value: 0x%x\n", + pdata->pi2c_reg[i].reg, pdata->pi2c_reg[i].val); + ret = cyttsp_write_reg(data, pdata->pi2c_reg[i].reg, pdata->pi2c_reg[i].val); + if (ret < 0) + LOG_INFO("reg write failed\n"); + i++; + } + + LOG_INFO("i2c reg set done\n"); +} + +static void cycapsense_hssp_notify(int status) +{ + programming_done = status; + blocking_notifier_call_chain(&hssp_notifier_list, + programming_done, NULL); +} + +int cycapsense_hssp_dnld(struct hssp_data *d) +{ + cycapsense_hssp_notify(HSSP_START); + + if (d->inf.data == NULL || d->inf.s_data == NULL) { + pr_err("%s: Invalid input arguments\n", __func__); + return -EINVAL; + } + + if (DeviceAcquire() == FAILURE) { + pr_err("%s: Device Acquire failed\n", __func__); + return -EIO; + } + + if (VerifySiliconId(d) == FAILURE) { + pr_err("%s: Verify Selicon ID failed\n", __func__); + return -EIO; + } + + if (EraseAllFlash(d) == FAILURE) { + pr_err("%s: Flash Erase failed\n", __func__); + return -EIO; + } + + if (ChecksumPrivileged(d) == FAILURE) { + pr_err("%s: Checksum Privileged failed\n", __func__); + return -EIO; + } + + if (ProgramFlash(d) == FAILURE) { + pr_err("%s: Program Flash failed\n", __func__); + return -EIO; + } + + if (VerifyFlash(d) == FAILURE) { + pr_err("%s: Verify Flash failed\n", __func__); + return -EIO; + } + + if (ProgramProtectionSettings(d) == FAILURE) { + pr_err("%s: Program Protection failed\n", __func__); + return -EIO; + } + + if (VerifyProtectionSettings(d) == FAILURE) { + pr_err("%s: Verify Protection failed\n", __func__); + return -EIO; + } + + if (VerifyChecksum(d) == FAILURE) { + pr_err("%s: Verify Checksum failed\n", __func__); + return -EIO; + } + + ExitProgrammingMode(); + msleep(1000); + cycapsense_hssp_notify(HSSP_STOP); + return SUCCESS; +} + +const unsigned char ascii2bin[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; +#define a_2_b(a) (ascii2bin[((a) & 0xff) - 0x30]) +#define a_a_2_byte(a1, a2) ((a_2_b(a1) << 4) | a_2_b(a2)) + +/* this simplifyied version of Intel HEX, Cypress PSoC specific*/ +int cycapsense_hssp_parse_hex(struct hssp_data *d, const u8 *src, int len) +{ + enum r_type { REC_DATA_T = 0, REC_EOF_T = 1, REC_EXT_L_ADDR_T = 4 }; + struct { int len; enum r_type type; int e_addr; } rec = { 0, 0, 0 }; + enum parser_state { REC_START, REC_LEN, REC_ADDR, REC_TYPE, REC_DATA, + REC_CS } state = REC_START; + int i = 0, j = 0, cnt; + u16 cs = 0, f_cs; + u8 *dst; + u8 rec_cs = 0, val; + + if (d == NULL) { + pr_err("%s: ID is not defined.\n", __func__); + return -EINVAL; + } + + cnt = d->block_size * d->num_of_blocks; + d->inf.data = kzalloc(cnt, GFP_KERNEL); + if (d->inf.data == NULL) { + pr_err("%s: Error kzalloc (%d).\n", __func__, cnt); + return -ENOMEM; + } + d->inf.s_data = kzalloc(d->secure_bytes, GFP_KERNEL); + if (d->inf.s_data == NULL) { + pr_err("%s: Error kzalloc (%d).\n", __func__, d->secure_bytes); + kfree(d->inf.data); + return -ENOMEM; + } + d->inf.m_data = kzalloc(P4000_METADATA_SIZE, GFP_KERNEL); + if (d->inf.m_data == NULL) { + pr_err("%s: Error kzalloc (%d).\n", __func__, + P4000_METADATA_SIZE); + kfree(d->inf.data); + return -ENOMEM; + } + dst = d->inf.data; /*data always first in PSoC HEX*/ + while (i < len) { + switch (state) { + case REC_START: + if (src[i] == '\r' || src[i] == '\n') + i++; + else if (src[i++] != ':') + goto parse_hex_end_err; + else + state = REC_LEN; + break; + case REC_LEN: + if (len - i < 2) + goto parse_hex_end_err; + rec.len = a_a_2_byte(src[i], src[i+1]); + i += 2; + rec_cs += rec.len; + state = REC_ADDR; + break; + case REC_ADDR: + if (len - i < 4) + goto parse_hex_end_err; + /* addr is not used by PSoC, only for check sum */ + val = a_a_2_byte(src[i], src[i+1]); + rec_cs += val; + val = a_a_2_byte(src[i+2], src[i+3]); + rec_cs += val; + i += 4; + state = REC_TYPE; + break; + case REC_TYPE: + if (len - i < 2) + goto parse_hex_end_err; + rec.type = a_a_2_byte(src[i], src[i+1]); + i += 2; + rec_cs += rec.type; + switch (rec.type) { + case REC_DATA_T: + state = REC_DATA; + break; + case REC_EXT_L_ADDR_T: + if (len - i < 4) + goto parse_hex_end_err; + val = a_a_2_byte(src[i], src[i+1]); + rec_cs += val; + rec.e_addr = val << 8; + val = a_a_2_byte(src[i+2], src[i+3]); + i += 4; + rec_cs += val; + rec.e_addr |= val; + if (rec.e_addr == 0x9030) { + /* Checksum */ + dst = (u8 *)&f_cs; + d->inf.cs = cs; + j = 0; + cnt = 2; + } else if (rec.e_addr == 0x9040) { + /* Flash protection */ + if (j > cnt) { + pr_err("%s: Too big for %s.\n", + __func__, d->name); + goto parse_hex_end_err; + } + dst = d->inf.s_data; + cnt = d->secure_bytes; + j = 0; + } else if (rec.e_addr == 0x9050) { + /* Metadata */ + j = 0; + dst = d->inf.m_data; + cnt = P4000_METADATA_SIZE; + } else if (rec.e_addr == 0x9060) { + /* Chip level protection */ + dst = (u8 *)&d->inf.cl_protection; + j = 0; + cnt = 1; + } else { + pr_err("%s: Unsupported ext addr 0x%x\n", + __func__, rec.e_addr); + goto parse_hex_end_err; + } + state = REC_CS; + break; + case REC_EOF_T: + if (be16_to_cpu(f_cs) != d->inf.cs) { + pr_err("%s: Data checksum failed 0x%x - 0x%x\n", + __func__, be16_to_cpu(f_cs), + d->inf.cs); + goto parse_hex_end_err; + } + state = REC_CS; + break; + default: /* Cypress supports only types above */ + pr_err("%s: Unsupported record type\n", + __func__); + goto parse_hex_end_err; + } + break; + case REC_DATA: + if (len - i < rec.len * 2) + goto parse_hex_end_err; + for (; rec.len; rec.len--, i += 2, dst++, j++) { + val = a_a_2_byte(src[i], src[i+1]); + if (j < cnt) { + *dst = val; + cs += val; + } + rec_cs += val; + } + state = REC_CS; + break; + case REC_CS: + if (len - i < 2) + goto parse_hex_end_err; + val = a_a_2_byte(src[i], src[i+1]); + i += 2; + rec_cs += val; + if (rec_cs != 0) { + pr_err("%s: Record check sum failed\n", + __func__); + goto parse_hex_end_err; + } + state = REC_START; + break; + } + } + return 0; +parse_hex_end_err: + pr_err("%s: HEX format error.\n", __func__); + kfree(d->inf.data); + d->inf.data = NULL; + kfree(d->inf.s_data); + d->inf.s_data = NULL; + kfree(d->inf.m_data); + d->inf.m_data = NULL; + return -EINVAL; +} + + +int __cycapsense_reset(struct cycapsense_ctrl_data *data) +{ + int status = programming_done; + + if (status == HSSP_STOP) + cycapsense_hssp_notify(HSSP_START); + + dev_info(data->dev, "Reset requested\n"); + device_lock(data->dev); + ExitProgrammingMode(); + msleep(1000); + + if (status == HSSP_STOP) + cycapsense_hssp_notify(HSSP_STOP); + + device_unlock(data->dev); + return 0; +} + +static int cycapsense_hssp_erase(struct hssp_data *d) +{ + cycapsense_hssp_notify(HSSP_START); + + device_lock(ctrl_data->dev); + if (DeviceAcquire() == FAILURE) { + pr_err("%s: Device Acquire failed\n", __func__); + return -EIO; + } + + if (EraseAllFlash(d) == FAILURE) { + pr_err("%s: Flash Erase failed\n", __func__); + return -EIO; + } + device_unlock(ctrl_data->dev); + d->chip_cs = 0; + pr_err("%s: Flash Erase successful\n", __func__); + return SUCCESS; +} + + +static int cycapsense_hssp_verify_swrev(struct hssp_data *d) +{ + int ret; + + cycapsense_hssp_notify(HSSP_START); + + if (DeviceAcquire() == FAILURE) { + pr_err("%s: Device Acquire failed\n", __func__); + ret = -EIO; + goto end; + } + + if (VerifySiliconId(d) == FAILURE) { + pr_err("%s: Verify Selicon ID failed\n", __func__); + ret = -EIO; + goto end; + } + + ret = VerifySwRevision(d); + +end: + ExitProgrammingMode(); + msleep(1000); + cycapsense_hssp_notify(HSSP_STOP); + return ret; +} + +int __cycapsense_fw_update(struct cycapsense_ctrl_data *data) +{ + const struct firmware *fw = NULL; + char *fw_name = NULL; + struct hex_info *inf; + int error = 0; + + inf = &data->hssp_d.inf; + + device_lock(data->dev); + + fw_name = kzalloc(NAME_MAX, GFP_KERNEL); + if (fw_name == NULL) { + dev_err(data->dev, "No memory for FW name\n"); + error = -ENOMEM; + goto fw_upd_end; + } + if (inf->fw_name[0] == 0) { + strlcpy(fw_name, data->hssp_d.name, NAME_MAX); + strlcat(fw_name, ".hex", NAME_MAX); + } else { + strlcpy(fw_name, inf->fw_name, NAME_MAX); + } + if (request_firmware(&fw, fw_name, data->dev) < 0 || !fw + || !fw->data || !fw->size) { + dev_err(data->dev, "Unable to get firmware %s\n", fw_name); + error = -ENOENT; + goto fw_upd_end; + } + error = cycapsense_hssp_parse_hex(&data->hssp_d, fw->data, + fw->size); + if (error) + goto fw_upd_end; + + if (cycapsense_hssp_verify_swrev(&data->hssp_d) != SUCCESS) { + + /* force update regardless check sum, if user requested */ + dev_info(data->dev, "Flashing firmware %s\n", fw_name); + fw_dl_status = 2; + error = cycapsense_hssp_dnld(&data->hssp_d); + if (!error) { + dev_info(data->dev, "%s flashed successful\n", + fw_name); + fw_dl_status = 0; + } else + fw_dl_status = 1; + } else { + data->hssp_d.chip_cs = data->hssp_d.inf.cs; + dev_info(data->dev, + "SW rev is matching. No firmware upgrade.\n"); + fw_dl_status = 0; + } + +fw_upd_end: + if (inf->data != NULL) { + kfree(inf->data); + inf->data = NULL; + } + if (inf->s_data != NULL) { + kfree(inf->s_data); + inf->s_data = NULL; + } + if (fw != NULL) + release_firmware(fw); + if (fw_name != NULL) + kfree(fw_name); + + device_unlock(data->dev); + return error; +} + +static int capsensor_set_enable(struct sensors_classdev *sensors_cdev, unsigned int enable) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + struct input_dev *input = data->input_dev[0]; + + if (enable == 1) { + LOG_INFO("enable cap sensor\n"); + hw_init(); + input_report_abs(input, ABS_DISTANCE, 0); + input_sync(input); + data->enable = true; + } else if (enable == 0) { + LOG_INFO("disable cap sensor\n"); + data->enable = false; + } else { + LOG_INFO("unknown enable symbol\n"); + } + + return 0; +} + + +/** + *fn static void cyttsp_reg_setup_init(struct i2c_client *client) + *brief read reg val form dts + * reg_array_len for regs needed change num + * data_array_val's format + */ +static void cyttsp_reg_setup_init(struct i2c_client *client) +{ + u32 data_array_len = 0; + u32 *data_array; + int ret, i, j; + struct device_node *np = client->dev.of_node; + + ret = of_property_read_u32(np, "reg_array_len", &data_array_len); + if (ret < 0) { + LOG_INFO("data_array_len read error"); + return; + } + data_array = kmalloc(data_array_len * 2 * sizeof(u32), GFP_KERNEL); + ret = of_property_read_u32_array(np, "reg_array_val", + data_array, + data_array_len*2); + if (ret < 0) { + LOG_INFO("data_array_val read error"); + return; + } + for (i = 0; i < ARRAY_SIZE(cyttsp_i2c_reg_setup); i++) { + for (j = 0; j < data_array_len*2; j += 2) { + if (data_array[j] == cyttsp_i2c_reg_setup[i].reg) + cyttsp_i2c_reg_setup[i].val = data_array[j+1]; + } + } + kfree(data_array); +} + +static int cyttsp_initialize_regulator(struct cyttsp_sar_data *data) +{ + int ret = 0; + struct i2c_client *client = data->client; + + data->regulator_vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->regulator_vdd)) { + dev_err(&client->dev, + "%s: regulator_get failed: %ld\n", + __func__, PTR_ERR(data->regulator_vdd)); + goto err_null_regulator; + } + + ret = regulator_enable(data->regulator_vdd); + if (ret < 0) { + dev_err(&client->dev, + "%s: regulator_enable failed: %d\n", + __func__, ret); + goto err_null_regulator; + } + + return 0; + +err_null_regulator: + data->regulator_vdd = NULL; + return ret; +} + +static void capsense_update_work(struct work_struct *w) +{ + struct cycapsense_ctrl_data *data = + container_of(w, struct cycapsense_ctrl_data, work); + + switch (data->cmd) { + case HSSP_CMD_RESET: + __cycapsense_reset(data); + break; + case HSSP_CMD_ERASE: + cycapsense_hssp_erase(&data->hssp_d); + break; + case HSSP_CMD_FW_UPDATE: + __cycapsense_fw_update(data); + break; + } + data->cmd = HSSP_CMD_NONE; +} + +int cycapsense_reset(void) +{ + if (ctrl_data == NULL || ctrl_data->dev == NULL) { + pr_err("%s: Ctrl data not initialized\n", __func__); + return -ENODEV; + } + + ctrl_data->cmd = HSSP_CMD_RESET; + schedule_work(&ctrl_data->work); + + return 0; +} + +static ssize_t cycapsense_fw_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 16, "0x%x\n", + ctrl_data && ctrl_data->hssp_d.chip_cs ? + ctrl_data->hssp_d.sw_rev : 0); +} + +static ssize_t cycapsense_fw_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + char *cp; + + if (!count) + return -EINVAL; + + cp = memchr(buf, '\n', count); + if (cp) + *(char *)cp = 0; + + if (!strcmp(buf, "reset")) + ctrl_data->cmd = HSSP_CMD_RESET; + else if (!strcmp(buf, "erase")) + ctrl_data->cmd = HSSP_CMD_ERASE; + else { + ctrl_data->cmd = HSSP_CMD_FW_UPDATE; + if (!strcmp(buf, "1")) + ctrl_data->hssp_d.inf.fw_name[0] = 0; + else + strlcpy(ctrl_data->hssp_d.inf.fw_name, buf, NAME_MAX); + } + + schedule_work(&ctrl_data->work); + + return count; +} + +static ssize_t cycapsense_reset_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 8, "%d\n", programming_done); +} + +static ssize_t cycapsense_reset_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + if (!count) + return -EINVAL; + + if (!strncmp(buf, "reset", 5) || !strncmp(buf, "1", 1)) + cycapsense_reset(); + + return count; +} + +static ssize_t cycapsense_enable_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + + return snprintf(buf, 8, "%d\n", (int)data->enable); + +} + +static ssize_t cycapsense_enable_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + struct cyttsp_sar_platform_data *pdata = data->pdata; + struct input_dev *input = NULL; + int i; + + if (!strncmp(buf, "1", 1)) { + LOG_INFO("enable cap sensor\n"); + hw_init(); + for (i = 0; i < pdata->nsars; i++) { + input = data->input_dev[i]; + input_report_abs(input, ABS_DISTANCE, 0); + input_sync(input); + } + data->enable = true; + } else if (!strncmp(buf, "0", 1)) { + LOG_INFO("disable cap sensor\n"); + + input_report_abs(input, ABS_DISTANCE, -1); + input_sync(input); + data->enable = false; + + } else { + LOG_INFO("unknown enable symbol\n"); + } + + return count; +} + +static ssize_t cycapsense_reg_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + u8 reg_value, reg = 0x00; + char *p = buf; + + while (reg <= 0x8a) { + reg_value = cyttsp_read_reg(data, reg); + p += snprintf(p, PAGE_SIZE, "ADDR(0x%02x)=0x%02x,\n", reg, reg_value); + reg++; + } + return (p-buf); +} + +static ssize_t cycapsense_reg_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + unsigned int val, reg; + int ret; + + if (sscanf(buf, "%x,%x", ®, &val) == 2) { + ret = cyttsp_write_reg(data, *((u8 *)®), *((u8 *)&val)); + } + + return count; +} + +static ssize_t cycapsense_debug_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cyttsp_sar_data *data = pcyttsp_sar_ptr; + u8 val1, val2, reg = 0x00; + u16 value1, value2; + int i, flag = 0; + + if (!strncmp(buf, "0", 1)) { + flag = 1; + LOG_INFO("read channel 0 data\n"); + for (i = 0; i < 200; i++) { + if (flag == 0) + break; + reg = 0x5b; + val1 = cyttsp_read_reg(data, reg); + reg = 0x5c; + val2 = cyttsp_read_reg(data, reg); + value1 = val2 << 8 | val1; + reg = 0x7b; + val1 = cyttsp_read_reg(data, reg); + reg = 0x7c; + val2 = cyttsp_read_reg(data, reg); + value2 = val2 << 8 | val1; + LOG_INFO(" raw = 0x%x, signal = 0x%x\n", value1, value2); + msleep(100); + + } + } else if (!strncmp(buf, "1", 1)) { + flag = 1; + LOG_INFO("read channel 1 data\n"); + for (i = 0; i < 200; i++) { + if (flag == 0) + break; + reg = 0x5d; + val1 = cyttsp_read_reg(data, reg); + reg = 0x5e; + val2 = cyttsp_read_reg(data, reg); + value1 = val2 << 8 | val1; + reg = 0x7d; + val1 = cyttsp_read_reg(data, reg); + reg = 0x7e; + val2 = cyttsp_read_reg(data, reg); + value2 = val2 << 8 | val1; + LOG_INFO(" raw = 0x%x, signal = 0x%x\n", value1, value2); + msleep(100); + + } + } else if (!strncmp(buf, "2", 1)) { + flag = 1; + LOG_INFO("read channel 2 data\n"); + for (i = 0; i < 200; i++) { + if (flag == 0) + break; + reg = 0x5f; + val1 = cyttsp_read_reg(data, reg); + reg = 0x60; + val2 = cyttsp_read_reg(data, reg); + value1 = val2 << 8 | val1; + reg = 0x7f; + val1 = cyttsp_read_reg(data, reg); + reg = 0x80; + val2 = cyttsp_read_reg(data, reg); + value2 = val2 << 8 | val1; + LOG_INFO(" raw = 0x%x, signal = 0x%x\n", value1, value2); + msleep(100); + + } + } else if (!strncmp(buf, "3", 1)) { + flag = 1; + LOG_INFO("read channel 3 data\n"); + for (i = 0; i < 200; i++) { + if (flag == 0) + break; + reg = 0x61; + val1 = cyttsp_read_reg(data, reg); + reg = 0x62; + val2 = cyttsp_read_reg(data, reg); + value1 = val2 << 8 | val1; + reg = 0x81; + val1 = cyttsp_read_reg(data, reg); + reg = 0x82; + val2 = cyttsp_read_reg(data, reg); + value2 = val2 << 8 | val1; + LOG_INFO(" raw = 0x%x, signal = 0x%x\n", value1, value2); + msleep(100); + } + } else if (!strncmp(buf, "4", 1)) { + flag = 0; + } + + return count; +} + +static ssize_t cycapsense_fw_download_status_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 8, "%d", fw_dl_status); +} + +static CLASS_ATTR(fw_update, 0660, cycapsense_fw_show, cycapsense_fw_store); +static CLASS_ATTR(reset, 0660, cycapsense_reset_show, cycapsense_reset_store); +static CLASS_ATTR(enable, 0660, cycapsense_enable_show, cycapsense_enable_store); +static CLASS_ATTR(reg, 0660, cycapsense_reg_show, cycapsense_reg_store); +static CLASS_ATTR(debug, 0660, NULL, cycapsense_debug_store); +static CLASS_ATTR(fw_download_status, 0660, cycapsense_fw_download_status_show, NULL); + +static struct class capsense_class = { + .name = "capsense", + .owner = THIS_MODULE, +}; + +static int cyttsp_sar_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cyttsp_sar_platform_data *pdata; + struct cyttsp_sar_data *data; + int error, i; + char *name; + char *buffer; + + dev_err(&client->dev, "cycapsense_probe enter\n"); + pdata = devm_kzalloc(&client->dev, + sizeof(struct cyttsp_sar_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memroy for pdata\n"); + return -ENOMEM; + } + + ctrl_data = devm_kzalloc(&client->dev, + sizeof(struct cycapsense_ctrl_data), GFP_KERNEL); + if (ctrl_data == NULL) { + dev_err(&client->dev, "Failed to allocate memory for ctrl_data\n"); + return -ENOMEM; + } + + error = cyttsp_sar_parse_dt(&client->dev, pdata); + if (error) + return error; + client->irq = pdata->irq_gpio; + + + cyttsp_reg_setup_init(client); + pdata->pi2c_reg = cyttsp_i2c_reg_setup; + pdata->i2c_reg_num = ARRAY_SIZE(cyttsp_i2c_reg_setup); + client->dev.platform_data = pdata; + + data = kzalloc(sizeof(struct cyttsp_sar_data), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Failed to allocate memory for data!\n"); + return -ENOMEM; + } + + data->client = client; + data->pdata = pdata; + pcyttsp_sar_ptr = data; + ctrl_data->dev = &client->dev; + + error = cyttsp_initialize_regulator(data); + if (error < 0) { + dev_err(&client->dev, "Failed to initialize regulator\n"); + goto err_free_data; + } + i2c_set_clientdata(data->client, data); + + for (i = 0; i < pdata->nsars; i++) { + /* Initialize input device */ + data->input_dev[i] = input_allocate_device(); + if (!data->input_dev[i]) { + dev_err(&client->dev, "Failed to allocate input device\n"); + goto err_irq_gpio_req; + } + name = kasprintf(GFP_KERNEL, "cyttsp_sar_ch%d", i); + + data->input_dev[i]->name = name; + + /* Set all the keycodes */ + __set_bit(EV_ABS, data->input_dev[i]->evbit); + input_set_abs_params(data->input_dev[i], ABS_DISTANCE, -1, 100, 0, 0); + + error = input_register_device(data->input_dev[i]); + if (error) { + dev_err(&client->dev, "Unable to register input %d device, error: %d\n", i, error); + goto err_free_input; + } + buffer = kasprintf(GFP_KERNEL, "Moto CapSense Ch%d", i); + sensors_capsensor_cdev[i].sensors_enable = capsensor_set_enable; + sensors_capsensor_cdev[i].sensors_poll_delay = NULL; + sensors_capsensor_cdev[i].name = buffer; + sensors_capsensor_cdev[i].vendor = "cypress"; + sensors_capsensor_cdev[i].version = 1; + sensors_capsensor_cdev[i].type = SENSOR_TYPE_MOTO_CAPSENSE; + sensors_capsensor_cdev[i].max_range = "5"; + sensors_capsensor_cdev[i].resolution = "5.0"; + sensors_capsensor_cdev[i].sensor_power = "3"; + sensors_capsensor_cdev[i].min_delay = 0; + sensors_capsensor_cdev[i].fifo_reserved_event_count = 0; + sensors_capsensor_cdev[i].fifo_max_event_count = 0; + sensors_capsensor_cdev[i].delay_msec = 100; + sensors_capsensor_cdev[i].enabled = 0; + + error = sensors_classdev_register(&data->input_dev[i]->dev, &sensors_capsensor_cdev[i]); + if (error < 0) + LOG_INFO("create %d cap sensor_class file failed (%d)\n", i, error); + + } + + error = request_threaded_irq(gpio_to_irq(client->irq), NULL, cyttsp_sar_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->dev.driver->name, data); + + + dev_err(&client->dev, "registering irq %d\n", gpio_to_irq(client->irq)); + if (error) { + dev_err(&client->dev, "Error %d registering irq %d\n", error, gpio_to_irq(client->irq)); + goto err_unreg_input; + } + + error = class_register(&capsense_class); + if (error < 0) { + dev_err(&client->dev, + "Create fsys class failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_fw_update); + if (error < 0) { + dev_err(&client->dev, + "Create fw_update file failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_reset); + if (error < 0) { + dev_err(&client->dev, + "Create reset file failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_reg); + if (error < 0) { + dev_err(&client->dev, + "Create reg file failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_enable); + if (error < 0) { + dev_err(&client->dev, + "Create enable file failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_debug); + if (error < 0) { + dev_err(&client->dev, + "Create debug file failed (%d)\n", error); + return error; + } + + error = class_create_file(&capsense_class, &class_attr_fw_download_status); + if (error < 0) { + dev_err(&client->dev, + "Create fw dl status file failed (%d)\n", error); + return error; + } + + fw_dl_status = 1; + ctrl_data->dev = &client->dev; + INIT_WORK(&ctrl_data->work, capsense_update_work); + gpio_direction_output(ctrl_data->hssp_d.rst_gpio, 0); + gpio_set_value(ctrl_data->hssp_d.rst_gpio, 1); + dev_dbg(&client->dev, "Cypress CapSense probe complete\n"); + + ctrl_data->cmd = HSSP_CMD_FW_UPDATE; + ctrl_data->hssp_d.inf.fw_name[0] = 0; + + schedule_work(&ctrl_data->work); + data->enable = false; + + return 0; + +err_unreg_input: + input_unregister_device(data->input_dev[0]); +err_free_input: + input_free_device(data->input_dev[i]); +err_irq_gpio_req: + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); +err_free_data: + kfree(data); + return error; +} + +static int cyttsp_sar_remove(struct i2c_client *client) +{ + struct cyttsp_sar_data *data = i2c_get_clientdata(client); + const struct cyttsp_sar_platform_data *pdata = data->pdata; + int i; + + free_irq(client->irq, data); + for (i = 0; i < 4; i++) { + input_unregister_device(data->input_dev[i]); + } + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); + if (data->regulator_vdd) + regulator_disable(data->regulator_vdd); + if (data->regulator_avdd) + regulator_disable(data->regulator_avdd); + if (data->regulator_vddio) + regulator_disable(data->regulator_vddio); + + kfree(data); + data = NULL; + + return 0; +} + +static void cyttsp_sar_shutdown(struct i2c_client *client) +{ + disable_irq(client->irq); +} + +static const struct i2c_device_id cyt_id[] = { + {"cyttsp_streetfighter", 0}, + { }, +}; + +#ifdef CONFIG_OF +static struct of_device_id cyttsp_match_table[] = { + { .compatible = "cypress,sf3155",}, + { }, +}; +#else +#define cyttsp_match_table NULL +#endif + +static struct i2c_driver cyttsp_sar_driver = { + .driver = { + .name = "cyttsp_streetfighter", + .owner = THIS_MODULE, + .of_match_table = cyttsp_match_table, + }, + .probe = cyttsp_sar_probe, + .remove = cyttsp_sar_remove, + .shutdown = cyttsp_sar_shutdown, + .id_table = cyt_id, +}; + +static int __init cyttsp_sar_init(void) +{ + return i2c_add_driver(&cyttsp_sar_driver); +} + +static void __exit cyttsp_sar_exit(void) +{ + i2c_del_driver(&cyttsp_sar_driver); +} + +late_initcall(cyttsp_sar_init); +module_exit(cyttsp_sar_exit); + +/* Module information */ +MODULE_AUTHOR("XXX "); +MODULE_DESCRIPTION("Cypress Capsense SAR Driver"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/hssp_programmer.h b/include/linux/hssp_programmer.h new file mode 100644 index 000000000000..c0e038d941d8 --- /dev/null +++ b/include/linux/hssp_programmer.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +void register_hssp_update_notify(struct notifier_block *nb); +void unregister_hssp_update_notify(struct notifier_block *nb); +int cycapsense_fw_update(void); +int cycapsense_reset(void); +/* +static inline void register_hssp_update_notify(struct notifier_block *nb) { } +static inline void unregister_hssp_update_notify(struct notifier_block *nb) { } +static inline int cycapsense_fw_update(void) { return 0; } +static inline int cycapsense_reset(void) { return 0; } +*/ +#define HSSP_START 0 +#define HSSP_STOP 1