diff options
Diffstat (limited to 'drivers/staging/westbridge/astoria/device')
4 files changed, 576 insertions, 0 deletions
diff --git a/drivers/staging/westbridge/astoria/device/Kconfig b/drivers/staging/westbridge/astoria/device/Kconfig new file mode 100644 index 0000000..cc99658 --- /dev/null +++ b/drivers/staging/westbridge/astoria/device/Kconfig @@ -0,0 +1,9 @@ +# +# West Bridge block driver configuration +# + +config WESTBRIDGE_DEVICE_DRIVER + tristate "West Bridge Device Driver" + help + Include the West Bridge based device driver + diff --git a/drivers/staging/westbridge/astoria/device/Makefile b/drivers/staging/westbridge/astoria/device/Makefile new file mode 100644 index 0000000..7af8b5b --- /dev/null +++ b/drivers/staging/westbridge/astoria/device/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for the kernel westbridge device driver +# + +ifneq ($(CONFIG_WESTBRIDGE_DEBUG),y) + EXTRA_CFLAGS += -DWESTBRIDGE_NDEBUG +endif + +obj-$(CONFIG_WESTBRIDGE_DEVICE_DRIVER) += cyasdev.o + + +ifeq ($(CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL),y) +#moved for staging compatbility +#cyasdev-y := ../../../arch/arm/mach-omap2/cyashalomap_kernel.o cyasdevice.o +cyasdev-y := ../arch/arm/mach-omap2/cyashalomap_kernel.o cyasdevice.o \ + ../api/src/cyasdma.o ../api/src/cyasintr.o ../api/src/cyaslep2pep.o \ + ../api/src/cyaslowlevel.o ../api/src/cyasmisc.o ../api/src/cyasmtp.o \ + ../api/src/cyasstorage.o ../api/src/cyasusb.o + +else +# should not get here, need to be built with some hal +cyasdev-y := cyasdevice.o +endif diff --git a/drivers/staging/westbridge/astoria/device/cyandevice_export.h b/drivers/staging/westbridge/astoria/device/cyandevice_export.h new file mode 100644 index 0000000..acb4e07 --- /dev/null +++ b/drivers/staging/westbridge/astoria/device/cyandevice_export.h @@ -0,0 +1,132 @@ +/* +## cyandevice_export.h - Linux Antioch device driver file +## +## =========================== +## Copyright (C) 2010 Cypress Semiconductor +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## 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. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street +## Fifth Floor, Boston, MA 02110-1301, USA. +## =========================== +*/ + +/* + * Export Misc APIs that can be used from the other driver modules. + * The APIs to create a device handle and download firmware are not exported + * because they are expected to be used only by this kernel module. + */ +EXPORT_SYMBOL(cy_as_misc_get_firmware_version); +EXPORT_SYMBOL(cy_as_misc_read_m_c_u_register); +EXPORT_SYMBOL(cy_as_misc_reset); +EXPORT_SYMBOL(cy_as_misc_acquire_resource); +EXPORT_SYMBOL(cy_as_misc_release_resource); +EXPORT_SYMBOL(cy_as_misc_enter_standby); +EXPORT_SYMBOL(cy_as_misc_leave_standby); +EXPORT_SYMBOL(cy_as_misc_enter_suspend); +EXPORT_SYMBOL(cy_as_misc_leave_suspend); +EXPORT_SYMBOL(cy_as_misc_storage_changed); +EXPORT_SYMBOL(cy_as_misc_heart_beat_control); +EXPORT_SYMBOL(cy_as_misc_get_gpio_value); +EXPORT_SYMBOL(cy_as_misc_set_gpio_value); +EXPORT_SYMBOL(cy_as_misc_set_low_speed_sd_freq); +EXPORT_SYMBOL(cy_as_misc_set_high_speed_sd_freq); + +/* + * Export the USB APIs that can be used by the dependent kernel modules. + */ +EXPORT_SYMBOL(cy_as_usb_set_end_point_config); +EXPORT_SYMBOL(cy_as_usb_read_data_async); +EXPORT_SYMBOL(cy_as_usb_write_data_async); +EXPORT_SYMBOL(cy_as_usb_cancel_async); +EXPORT_SYMBOL(cy_as_usb_set_stall); +EXPORT_SYMBOL(cy_as_usb_clear_stall); +EXPORT_SYMBOL(cy_as_usb_connect); +EXPORT_SYMBOL(cy_as_usb_disconnect); +EXPORT_SYMBOL(cy_as_usb_start); +EXPORT_SYMBOL(cy_as_usb_stop); +EXPORT_SYMBOL(cy_as_usb_set_enum_config); +EXPORT_SYMBOL(cy_as_usb_get_enum_config); +EXPORT_SYMBOL(cy_as_usb_set_physical_configuration); +EXPORT_SYMBOL(cy_as_usb_register_callback); +EXPORT_SYMBOL(cy_as_usb_commit_config); +EXPORT_SYMBOL(cy_as_usb_set_descriptor); +EXPORT_SYMBOL(cy_as_usb_clear_descriptors); +EXPORT_SYMBOL(cy_as_usb_get_descriptor); +EXPORT_SYMBOL(cy_as_usb_get_end_point_config); +EXPORT_SYMBOL(cy_as_usb_read_data); +EXPORT_SYMBOL(cy_as_usb_write_data); +EXPORT_SYMBOL(cy_as_usb_get_stall); +EXPORT_SYMBOL(cy_as_usb_set_nak); +EXPORT_SYMBOL(cy_as_usb_clear_nak); +EXPORT_SYMBOL(cy_as_usb_get_nak); +EXPORT_SYMBOL(cy_as_usb_signal_remote_wakeup); +EXPORT_SYMBOL(cy_as_usb_set_m_s_report_threshold); +EXPORT_SYMBOL(cy_as_usb_select_m_s_partitions); + +/* + * Export all Storage APIs that can be used by dependent kernel modules. + */ +EXPORT_SYMBOL(cy_as_storage_start); +EXPORT_SYMBOL(cy_as_storage_stop); +EXPORT_SYMBOL(cy_as_storage_register_callback); +EXPORT_SYMBOL(cy_as_storage_query_bus); +EXPORT_SYMBOL(cy_as_storage_query_media); +EXPORT_SYMBOL(cy_as_storage_query_device); +EXPORT_SYMBOL(cy_as_storage_query_unit); +EXPORT_SYMBOL(cy_as_storage_device_control); +EXPORT_SYMBOL(cy_as_storage_claim); +EXPORT_SYMBOL(cy_as_storage_release); +EXPORT_SYMBOL(cy_as_storage_read); +EXPORT_SYMBOL(cy_as_storage_write); +EXPORT_SYMBOL(cy_as_storage_read_async); +EXPORT_SYMBOL(cy_as_storage_write_async); +EXPORT_SYMBOL(cy_as_storage_cancel_async); +EXPORT_SYMBOL(cy_as_storage_sd_register_read); +EXPORT_SYMBOL(cy_as_storage_create_p_partition); +EXPORT_SYMBOL(cy_as_storage_remove_p_partition); +EXPORT_SYMBOL(cy_as_storage_get_transfer_amount); +EXPORT_SYMBOL(cy_as_storage_erase); + +EXPORT_SYMBOL(cy_as_sdio_query_card); +EXPORT_SYMBOL(cy_as_sdio_init_function); +EXPORT_SYMBOL(cy_as_sdio_set_blocksize); +EXPORT_SYMBOL(cy_as_sdio_direct_read); +EXPORT_SYMBOL(cy_as_sdio_direct_write); +EXPORT_SYMBOL(cy_as_sdio_extended_read); +EXPORT_SYMBOL(cy_as_sdio_extended_write); + +EXPORT_SYMBOL(cy_as_hal_alloc); +EXPORT_SYMBOL(cy_as_hal_free); +EXPORT_SYMBOL(cy_as_hal_sleep); +EXPORT_SYMBOL(cy_as_hal_create_sleep_channel); +EXPORT_SYMBOL(cy_as_hal_destroy_sleep_channel); +EXPORT_SYMBOL(cy_as_hal_sleep_on); +EXPORT_SYMBOL(cy_as_hal_wake); +EXPORT_SYMBOL(cy_as_hal_mem_set); + +EXPORT_SYMBOL(cy_as_mtp_storage_only_start); +EXPORT_SYMBOL(cy_as_mtp_storage_only_stop); +EXPORT_SYMBOL(cy_as_mtp_start); +EXPORT_SYMBOL(cy_as_mtp_init_send_object); +EXPORT_SYMBOL(cy_as_mtp_init_get_object); +EXPORT_SYMBOL(cy_as_mtp_cancel_send_object); +EXPORT_SYMBOL(cy_as_mtp_cancel_get_object); + +#ifdef __CY_ASTORIA_SCM_KERNEL_HAL__ +/* Functions in the SCM kernel HAL implementation only. */ +EXPORT_SYMBOL(cy_as_hal_enable_scatter_list); +EXPORT_SYMBOL(cy_as_hal_disable_scatter_list); +#endif + +/*[]*/ diff --git a/drivers/staging/westbridge/astoria/device/cyasdevice.c b/drivers/staging/westbridge/astoria/device/cyasdevice.c new file mode 100644 index 0000000..c76e383 --- /dev/null +++ b/drivers/staging/westbridge/astoria/device/cyasdevice.c @@ -0,0 +1,412 @@ +/* +## cyandevice.c - Linux Antioch device driver file +## =========================== +## Copyright (C) 2010 Cypress Semiconductor +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## 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. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor +## Boston, MA 02110-1301, USA. +## =========================== +*/ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/sched.h> +#include <linux/scatterlist.h> +#include <linux/err.h> +#include <linux/firmware.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* moved for staging location + * update/patch submission +#include <linux/westbridge/cyastoria.h> +#include <linux/westbridge/cyashal.h> +#include <linux/westbridge/cyasregs.h> +*/ + +#include "../include/linux/westbridge/cyastoria.h" +#include "../include/linux/westbridge/cyashal.h" +#include "../include/linux/westbridge/cyasregs.h" + +/* API exports include file */ +#include "cyandevice_export.h" + +typedef struct cyasdevice { + /* Handle to the Antioch device */ + cy_as_device_handle dev_handle; + /* Handle to the HAL */ + cy_as_hal_device_tag hal_tag; + spinlock_t common_lock; + unsigned long flags; +} cyasdevice; + +/* global ptr to astoria device */ +static cyasdevice *cy_as_device_controller; +int cy_as_device_init_done; +const char *dev_handle_name = "cy_astoria_dev_handle"; + +#ifdef CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL +extern void cy_as_hal_config_c_s_mux(void); +#endif + +static void cyasdevice_deinit(cyasdevice *cy_as_dev) +{ + cy_as_hal_print_message("<1>_cy_as_device deinitialize called\n"); + if (!cy_as_dev) { + cy_as_hal_print_message("<1>_cy_as_device_deinit: " + "device handle %x is invalid\n", (uint32_t)cy_as_dev); + return; + } + + /* stop west_brige */ + if (cy_as_dev->dev_handle) { + cy_as_hal_print_message("<1>_cy_as_device: " + "cy_as_misc_destroy_device called\n"); + if (cy_as_misc_destroy_device(cy_as_dev->dev_handle) != + CY_AS_ERROR_SUCCESS) { + cy_as_hal_print_message( + "<1>_cy_as_device: destroying failed\n"); + } + } + + if (cy_as_dev->hal_tag) { + + #ifdef CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL + if (stop_o_m_a_p_kernel(dev_handle_name, + cy_as_dev->hal_tag) != 0) + cy_as_hal_print_message("<1>_cy_as_device: stopping " + "OMAP kernel HAL failed\n"); + + #endif + } + cy_as_hal_print_message("<1>_cy_as_device:HAL layer stopped\n"); + + kfree(cy_as_dev); + cy_as_device_controller = NULL; + cy_as_hal_print_message("<1>_cy_as_device: deinitialized\n"); +} + +/*called from src/cyasmisc.c:MyMiscCallback() as a func + * pointer [dev_p->misc_event_cb] which was previously + * registered by CyAsLLRegisterRequestCallback(..., + * MyMiscCallback); called from CyAsMiscConfigureDevice() + * which is in turn called from cyasdevice_initialize() in + * this src + */ +static void cy_misc_callback(cy_as_device_handle h, + cy_as_misc_event_type evtype, void *evdata) +{ + (void)h; + (void)evdata; + + switch (evtype) { + case cy_as_event_misc_initialized: + cy_as_hal_print_message("<1>_cy_as_device: " + "initialization done callback triggered\n"); + cy_as_device_init_done = 1; + break; + + case cy_as_event_misc_awake: + cy_as_hal_print_message("<1>_cy_as_device: " + "cy_as_event_misc_awake event callback triggered\n"); + cy_as_device_init_done = 1; + break; + default: + break; + } +} + +void cy_as_acquire_common_lock() +{ + spin_lock_irqsave(&cy_as_device_controller->common_lock, + cy_as_device_controller->flags); +} +EXPORT_SYMBOL(cy_as_acquire_common_lock); + +void cy_as_release_common_lock() +{ + spin_unlock_irqrestore(&cy_as_device_controller->common_lock, + cy_as_device_controller->flags); +} +EXPORT_SYMBOL(cy_as_release_common_lock); + +/* reset astoria and reinit all regs */ + #define PNAND_REG_CFG_INIT_VAL 0x0000 +void hal_reset(cy_as_hal_device_tag tag) +{ + cy_as_hal_print_message("<1> send soft hard rst: " + "MEM_RST_CTRL_REG_HARD...\n"); + cy_as_hal_write_register(tag, CY_AS_MEM_RST_CTRL_REG, + CY_AS_MEM_RST_CTRL_REG_HARD); + mdelay(60); + + cy_as_hal_print_message("<1> after RST: si_rev_REG:%x, " + "PNANDCFG_reg:%x\n", + cy_as_hal_read_register(tag, CY_AS_MEM_CM_WB_CFG_ID), + cy_as_hal_read_register(tag, CY_AS_MEM_PNAND_CFG) + ); + + /* set it to LBD */ + cy_as_hal_write_register(tag, CY_AS_MEM_PNAND_CFG, + PNAND_REG_CFG_INIT_VAL); +} +EXPORT_SYMBOL(hal_reset); + + +/* below structures and functions primarily + * implemented for firmware loading */ +static struct platform_device *westbridge_pd; + +static int __devinit wb_probe(struct platform_device *devptr) +{ + cy_as_hal_print_message("%s called\n", __func__); + return 0; +} + +static int __devexit wb_remove(struct platform_device *devptr) +{ + cy_as_hal_print_message("%s called\n", __func__); + return 0; +} + +static struct platform_driver west_bridge_driver = { + .probe = wb_probe, + .remove = __devexit_p(wb_remove), + .driver = { + .name = "west_bridge_dev"}, +}; + +/* west bridge device driver main init */ +static int cyasdevice_initialize(void) +{ + cyasdevice *cy_as_dev = 0; + int ret = 0; + int retval = 0; + cy_as_device_config config; + cy_as_hal_sleep_channel channel; + cy_as_get_firmware_version_data ver_data = {0}; + const char *str = ""; + int spin_lim; + const struct firmware *fw_entry; + + cy_as_device_init_done = 0; + + cy_as_misc_set_log_level(8); + + cy_as_hal_print_message("<1>_cy_as_device initialize called\n"); + + if (cy_as_device_controller != 0) { + cy_as_hal_print_message("<1>_cy_as_device: the device " + "has already been initilaized. ignoring\n"); + return -EBUSY; + } + + /* cy_as_dev = CyAsHalAlloc (sizeof(cyasdevice), SLAB_KERNEL); */ + cy_as_dev = cy_as_hal_alloc(sizeof(cyasdevice)); + if (cy_as_dev == NULL) { + cy_as_hal_print_message("<1>_cy_as_device: " + "memmory allocation failed\n"); + return -ENOMEM; + } + memset(cy_as_dev, 0, sizeof(cyasdevice)); + + + /* Init the HAL & CyAsDeviceHandle */ + + #ifdef CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL + /* start OMAP HAL init instsnce */ + + if (!start_o_m_a_p_kernel(dev_handle_name, + &(cy_as_dev->hal_tag), cy_false)) { + + cy_as_hal_print_message( + "<1>_cy_as_device: start OMAP34xx HAL failed\n"); + goto done; + } + #endif + + /* Now create the device */ + if (cy_as_misc_create_device(&(cy_as_dev->dev_handle), + cy_as_dev->hal_tag) != CY_AS_ERROR_SUCCESS) { + + cy_as_hal_print_message( + "<1>_cy_as_device: create device failed\n"); + goto done; + } + + memset(&config, 0, sizeof(config)); + config.dmaintr = cy_true; + + ret = cy_as_misc_configure_device(cy_as_dev->dev_handle, &config); + if (ret != CY_AS_ERROR_SUCCESS) { + + cy_as_hal_print_message( + "<1>_cy_as_device: configure device " + "failed. reason code: %d\n", ret); + goto done; + } + + ret = cy_as_misc_register_callback(cy_as_dev->dev_handle, + cy_misc_callback); + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_hal_print_message("<1>_cy_as_device: " + "cy_as_misc_register_callback failed. " + "reason code: %d\n", ret); + goto done; + } + + ret = platform_driver_register(&west_bridge_driver); + if (unlikely(ret < 0)) + return ret; + westbridge_pd = platform_device_register_simple( + "west_bridge_dev", -1, NULL, 0); + + if (IS_ERR(westbridge_pd)) { + platform_driver_unregister(&west_bridge_driver); + return PTR_ERR(westbridge_pd); + } + /* Load the firmware */ + ret = request_firmware(&fw_entry, + "west bridge fw", &westbridge_pd->dev); + if (ret) { + cy_as_hal_print_message("cy_as_device: " + "request_firmware failed return val = %d\n", ret); + } else { + cy_as_hal_print_message("cy_as_device: " + "got the firmware %d size=0x%x\n", ret, fw_entry->size); + + ret = cy_as_misc_download_firmware( + cy_as_dev->dev_handle, + fw_entry->data, + fw_entry->size , + 0, 0); + } + + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_hal_print_message("<1>_cy_as_device: cannot download " + "firmware. reason code: %d\n", ret); + goto done; + } + + /* spin until the device init is completed */ + /* 50 -MAX wait time for the FW load & init + * to complete is 5sec*/ + spin_lim = 50; + + cy_as_hal_create_sleep_channel(&channel); + while (!cy_as_device_init_done) { + + cy_as_hal_sleep_on(&channel, 100); + + if (spin_lim-- <= 0) { + cy_as_hal_print_message( + "<1>\n_e_r_r_o_r!: " + "wait for FW init has timed out !!!"); + break; + } + } + cy_as_hal_destroy_sleep_channel(&channel); + + if (spin_lim > 0) + cy_as_hal_print_message( + "cy_as_device: astoria firmware is loaded\n"); + + ret = cy_as_misc_get_firmware_version(cy_as_dev->dev_handle, + &ver_data, 0, 0); + if (ret != CY_AS_ERROR_SUCCESS) { + cy_as_hal_print_message("<1>_cy_as_device: cannot get firmware " + "version. reason code: %d\n", ret); + goto done; + } + + if ((ver_data.media_type & 0x01) && (ver_data.media_type & 0x06)) + str = "nand and SD/MMC."; + else if ((ver_data.media_type & 0x01) && (ver_data.media_type & 0x08)) + str = "nand and CEATA."; + else if (ver_data.media_type & 0x01) + str = "nand."; + else if (ver_data.media_type & 0x08) + str = "CEATA."; + else + str = "SD/MMC."; + + cy_as_hal_print_message("<1> cy_as_device:_firmware version: %s " + "major=%d minor=%d build=%d,\n_media types supported:%s\n", + ((ver_data.is_debug_mode) ? "debug" : "release"), + ver_data.major, ver_data.minor, ver_data.build, str); + + spin_lock_init(&cy_as_dev->common_lock); + + /* done now */ + cy_as_device_controller = cy_as_dev; + + return 0; + +done: + if (cy_as_dev) + cyasdevice_deinit(cy_as_dev); + + return -EINVAL; +} + +cy_as_device_handle cyasdevice_getdevhandle(void) +{ + if (cy_as_device_controller) { + #ifdef CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL + cy_as_hal_config_c_s_mux(); + #endif + + return cy_as_device_controller->dev_handle; + } + return NULL; +} +EXPORT_SYMBOL(cyasdevice_getdevhandle); + +cy_as_hal_device_tag cyasdevice_gethaltag(void) +{ + if (cy_as_device_controller) + return (cy_as_hal_device_tag) + cy_as_device_controller->hal_tag; + + return NULL; +} +EXPORT_SYMBOL(cyasdevice_gethaltag); + + +/*init Westbridge device driver **/ +static int __init cyasdevice_init(void) +{ + if (cyasdevice_initialize() != 0) + return ENODEV; + + return 0; +} + + +static void __exit cyasdevice_cleanup(void) +{ + + cyasdevice_deinit(cy_as_device_controller); +} + + +MODULE_DESCRIPTION("west bridge device driver"); +MODULE_AUTHOR("cypress semiconductor"); +MODULE_LICENSE("GPL"); + +module_init(cyasdevice_init); +module_exit(cyasdevice_cleanup); + +/*[]*/ |