diff options
author | Hyun myung Cho <hm83.cho@samsung.com> | 2016-06-30 16:01:46 +0900 |
---|---|---|
committer | Hyun myung Cho <hm83.cho@samsung.com> | 2016-06-30 16:01:46 +0900 |
commit | 99ca6a81497c5b4b34f907b9c7a6c025843d6d43 (patch) | |
tree | 7b081bba0afc7d6da7c21ce86239b39d0dfb5864 | |
parent | 6b7d3aebe881dc9f6afbd3fc44be8d3ffc0f0300 (diff) | |
download | emulator-kernel-99ca6a81497c5b4b34f907b9c7a6c025843d6d43.tar.gz emulator-kernel-99ca6a81497c5b4b34f907b9c7a6c025843d6d43.tar.bz2 emulator-kernel-99ca6a81497c5b4b34f907b9c7a6c025843d6d43.zip |
TV: Add dummy driver for TV Emulator
Change-Id: I09cb1b1a5b4b45a2b743218b552603685ae1c1e5
Signed-off-by: Hyun myung Cho <hm83.cho@samsung.com>
-rw-r--r-- | arch/x86/configs/tizen_emul_defconfig | 8 | ||||
-rw-r--r-- | drivers/maru/Kconfig | 31 | ||||
-rw-r--r-- | drivers/maru/Makefile | 2 | ||||
-rw-r--r-- | drivers/maru/maru_eeprom.c | 705 | ||||
-rw-r--r-- | drivers/maru/maru_eeprom.h | 61 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/Makefile | 7 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy.c | 219 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy.h | 52 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_gpio.c | 196 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_i2c_sdp.c | 278 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_micom_isp.c | 269 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_micom_msg.c | 356 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_sdp_mem.c | 174 | ||||
-rw-r--r-- | drivers/maru/tztv-dummy/maru_dummy_security.c | 202 |
14 files changed, 2560 insertions, 0 deletions
diff --git a/arch/x86/configs/tizen_emul_defconfig b/arch/x86/configs/tizen_emul_defconfig index d518262da321..76806aebe736 100644 --- a/arch/x86/configs/tizen_emul_defconfig +++ b/arch/x86/configs/tizen_emul_defconfig @@ -3454,6 +3454,14 @@ CONFIG_MARU_VIRTIO_NFC=y CONFIG_MARU_BRILLCODEC=y CONFIG_MARU_VIRTIO_VMODEM=y CONFIG_MARU_VIRTIO_ROTARY=y +CONFIG_MARU_EEPROM=y +CONFIG_MARU_MICOM_MSG=y +CONFIG_MARU_MICOM_ISP=y +CONFIG_MARU_DUMMY=y +CONFIG_MARU_SECURITY=y +CONFIG_MARU_SDP_MEM=y +CONFIG_MARU_GPIO=y +CONFIG_MARU_I2C_SDP=y # CONFIG_MARU_EXTENSION_SOURCE is not set # diff --git a/drivers/maru/Kconfig b/drivers/maru/Kconfig index 623b349a32fe..efe071060be3 100644 --- a/drivers/maru/Kconfig +++ b/drivers/maru/Kconfig @@ -69,3 +69,34 @@ config MARU_EXTENSION_SOURCE config MARU_EXTENSION_SOURCE_PATH string "MARU Extension source path" depends on MARU != n && MARU_EXTENSION_SOURCE != n + +config MARU_MICOM_MSG + tristate "Micom Auto Remocon driver support for WT61P807" + +config MARU_MICOM_ISP + tristate "Micom ISP data support for WT61P807" + +config MARU_DUMMY + tristate "MARU Dummy Driver" + depends on MARU != n + +config MARU_SECURITY + tristate "MARU Security Driver" + depends on MARU != n + +config MARU_SDP_MEM + tristate "MARU SDP Memory Driver" + depends on MARU != n + +config MARU_GPIO + tristate "MARU Dummy GPIO Driver" + depends on MARU != n && GPIOLIB != n + +config MARU_I2C_SDP + tristate "Maru Dummy I2C SDP Driver" + depends on MARU != n && I2C != n + +config MARU_EEPROM + tristate "MARU VirtIO Virtual EEPROM Device Driver" + depends on MARU != n + depends on SYSFS diff --git a/drivers/maru/Makefile b/drivers/maru/Makefile index 5b2d4976dd29..a1627f8007c9 100644 --- a/drivers/maru/Makefile +++ b/drivers/maru/Makefile @@ -15,4 +15,6 @@ obj-$(CONFIG_MARU_BRILLCODEC) += maru_brillcodec.o obj-$(CONFIG_MARU_VIRTIO_VMODEM) += maru_virtio_vmodem.o obj-$(CONFIG_MARU_VIRTIO_ROTARY) += maru_virtio_rotary.o obj-$(CONFIG_MARU_VIRTIO_TABLET) += maru_virtio_tablet.o +obj-$(CONFIG_MARU_EEPROM) += maru_eeprom.o +obj-$(CONFIG_MARU_DUMMY) += tztv-dummy/ obj-$(CONFIG_MARU_EXTENSION_SOURCE) += $(CONFIG_MARU_EXTENSION_SOURCE_PATH)/ diff --git a/drivers/maru/maru_eeprom.c b/drivers/maru/maru_eeprom.c new file mode 100644 index 000000000000..9baccf00a38d --- /dev/null +++ b/drivers/maru/maru_eeprom.c @@ -0,0 +1,705 @@ +/* + * MARU EEPROM + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Dongkyun Yun <dk77.yun@samsung.com> + * Munkyu Im <munkyu.im@samsung.com> + * Sangho Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/jiffies.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/of_gpio.h> +#include <linux/version.h> +#include <linux/moduleparam.h> +#include <linux/cdev.h> +#include <linux/file.h> +#include "maru_eeprom.h" +#include <linux/vmalloc.h> + +//#define EEP_DEBUG + +#ifdef EEP_DEBUG +#define eep_log(fmt, arg...) \ + printk(KERN_INFO "[%s](%s:%d)[%s:%d]: " fmt, EEPROM_DEV_NAME, \ + __func__, __LINE__, current->comm, current->pid, ##arg); +#else +#define eep_log(fmt, arg...) +#endif + +#define eep_err(fmt, arg...) \ + printk(KERN_ERR "[%s](%s)[%s:%d]: " fmt, EEPROM_DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); +#define eep_warn(fmt, arg...) \ + printk(KERN_WARNING "[%s](%s)[%s:%d]: " fmt, EEPROM_DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); +#define eep_info(fmt, arg...) \ + printk(KERN_INFO "[%s](%s:%d)[%s:%d]: " fmt, EEPROM_DEV_NAME, __func__, __LINE__, \ + current->comm, current->pid, ##arg); + + + +#define FILENAME "/boot/eeprom" + +#define true 1 +#define false 0 + +/* device protocol */ +enum req_cmd { + req_eeprom_get = 1, + req_eeprom_set, + req_eeprom_reply +}; + +/* eeprom specific macros */ +#define EEP_BLOCK_SIZE 4096 +#define EEP_BLOCK_COUNT 16 +#define EEPROM_MAX_SIZE (EEP_BLOCK_SIZE * EEP_BLOCK_COUNT) +#define MAX_ATTR_BYTES 6 + +/* 10 milliseconds of delay is required after each i2c write operation */ +//#define DELAY 10000 + +/* upper/lower 8-bit word address macros */ +#define HI_BYTE(x) (((x) >> 8) & (0x00FF)) +#define LO_BYTE(x) ((x) & (0x00FF)) + +/* define global mutex statically ***/ +static DEFINE_MUTEX(eep_mutex); + +/* global variables for this module ***/ +static int counter; +static const unsigned int eeprom_size = EEPROM_MAX_SIZE; +static int eeprom_dev_major; +//static struct i2c_client *eep_client; + +/* write protection for eeprom */ +static int g_protect; + +static struct file *g_file; + +static ssize_t eeprom_write_file(const unsigned char __user *buf, int len, loff_t pos) +{ + ssize_t ret = 0; + mm_segment_t old_fs; + + if (g_file == NULL) + return -ENODEV; + + if (g_protect) { + eep_info("memory is protected.\n"); + return ret; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + + ret = vfs_write(g_file, buf, len, &pos); + if (ret != len) { + eep_warn("len mismatch len: %d, ret: %d, pos: %lld\n", ret, len, pos); + } + set_fs(old_fs); + + return ret; +} + +static int eeprom_init_file(void) +{ + unsigned int i; + loff_t pos = 0; + int ret = 0; + int reminder_pos = 0; + unsigned char *buf = vmalloc(EEP_BLOCK_SIZE); + if (!buf) { + eep_warn("memory not allocated for buffer.\n"); + ret = -ENOMEM; + goto out_ext; + } + memset(buf, 0xff, EEP_BLOCK_SIZE); + + for (i = 0; i < EEP_BLOCK_COUNT; i++) { + ret = eeprom_write_file(buf, EEP_BLOCK_SIZE, pos); + if (ret < 0) { + eep_warn("failed to initialize. ret: %d\n", ret); + goto out_ext; + } else if (ret < EEP_BLOCK_SIZE) { + eep_info("write reminder.\n"); + reminder_pos = ret; + do { + ret = eeprom_write_file(buf, EEP_BLOCK_SIZE - reminder_pos, pos + reminder_pos); + if (ret <= 0) { + eep_warn("failed to write reminder. ret: %d\n", ret); + goto out_ext; + } + reminder_pos += ret; + } while (reminder_pos != EEP_BLOCK_SIZE); + } + pos += EEP_BLOCK_SIZE; + } + ret = pos; + vfree(buf); + eep_info("file initialized: %s\n", FILENAME); + +out_ext: + return ret; +} + +static int eeprom_open_file(void) +{ + struct file *file; + eep_log("eeprom_open_file\n"); + + file = filp_open(FILENAME, O_CREAT|O_RDWR|O_EXCL|O_SYNC, 0666); + if (IS_ERR(file)) { + eep_info("file already exists: %s\n", FILENAME); + file = filp_open(FILENAME, O_CREAT|O_RDWR|O_SYNC, 0666); + if (IS_ERR(file)) { + eep_warn("filp_open failed.\n"); + return -ENOENT; + } + g_file = file; + return 0; + } + g_file = file; + + return eeprom_init_file(); +} + +static ssize_t eeprom_read_file(unsigned char __user *buf, int len, loff_t pos) +{ + ssize_t ret = 0; + mm_segment_t old_fs; + + if (g_file == NULL) + return -ENODEV; + + eep_log("pos(%lld) len(%d) \n", pos, len); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + ret = vfs_read(g_file, buf, len, &pos); + if (ret != len) { + eep_warn("len mismatch len: %d, ret: %d, pos: %lld\n", ret, len, pos); + } + set_fs(old_fs); + + return ret; +} + +static int eeprom_usr_write(const char __user *buf, size_t count, unsigned long addr) +{ + int ret = -EFAULT; + + eep_log("eep write.\n"); + if (!buf) { + eep_err("Invalid User buffer.\n"); + } else if (count > 0) { + if (addr + count > eeprom_size) { + eep_err("overflow!!.\n"); + goto out_err; + } + ret = eeprom_write_file(buf, count, addr); + if (ret < 0) { + eep_warn("Write failed.\n"); + } + } else { + eep_warn("inavalid count.\n"); + } + +out_err: + return ret; +} + +static ssize_t eeprom_usr_read(char __user *buf, size_t count, unsigned long addr) +{ + int ret = -EFAULT; + + eep_log("eep read.\n"); + if (!buf) { + eep_err("User buf has no memory allocation.\n"); + } else if (count > 0) { + if (count + addr > eeprom_size) { + eep_err("overflow!!.\n"); + goto out_err; + } + ret = eeprom_read_file(buf, count, addr); + if (ret < 0) { + eep_warn("read failed.\n"); + } + } else { + eep_warn("invalid count.\n"); + } + +out_err: + return ret; +} + + + + +/* for using sysfs. (class, device, device attribute) */ + +/** @brief This function inhibits the write operation on eeprom. + * + * @param [in] protect value(0 or 1). + * 1 - To protect memory. + * 0 - To unprotect memory. + * @return On success Returns 0. + * On failure Returns negative error number. + */ +int eep_set_wp(int protect) +{ + int ret = 0; + + if (protect != 0 && protect != 1) { + eep_warn("invalid input.\n"); + return -EINVAL; + } + + g_protect = protect; + eep_log("eeprom => %d (1:locked, 0:unlocked)\n", g_protect); + + return ret; +} +EXPORT_SYMBOL(eep_set_wp); + +/** + * @brief Returns the status of eeprom write protection. + * + * @param [in] void It takes no arguments. + * + * @return On success Returns 0. + * On failure Returns negative error number. + */ +int eep_get_wp() +{ + int ret = 0; + + ret = g_protect; + eep_log("eeprom => %d (1:locked, 0:unlocked)\n", g_protect); + + return ret; +} +EXPORT_SYMBOL(eep_get_wp); + +/** + * @brief This function resets the whole eeprom chip. + * + * @parms [in] void It takes no arguments. + * + * @return On success Returns 0. + * On failure Returns negative error number. + */ +static int eep_reset(void) +{ + return eeprom_init_file(); +} + +/** + * @brief This function opens the eeprom device. + * + * @param inode inode. + * @param [in] fp File pointer points to the file descriptor. + * + * @return On success Returns 0. + * On failure Returns negative error number. + */ +int eep_open(struct inode *inode, struct file *fp) +{ + int ret = 0; + + mutex_lock(&eep_mutex); + if (counter == 0) { + eeprom_open_file(); + } else if (g_file == NULL) { + eep_warn("g_file is NULL\n"); + ret = -ENODEV; + goto out; + } else { + //Increase reference count of g_file + atomic_long_inc_not_zero(&g_file->f_count); + } + + counter++; + eep_log("Open: #:%d\n" , counter); + //eep_log("major number=%d, minor number=%d \n", imajor(inode), iminor(inode)); +out: + mutex_unlock(&eep_mutex); + + return ret; +} + +/** + * @brief This function undo the all open call operations. + * + * @param inode inode. + * @param [in] fp File pointer points to the file descriptor. + * + * @return On success Returns 0. + * On failure Returns negative error number. + */ +int eep_close(struct inode *inode, struct file *fp) +{ + int ret = 0; + + eep_log("close.\n"); + + mutex_lock(&eep_mutex); + BUG_ON(g_file == NULL); + fput(g_file); + counter--; + mutex_unlock(&eep_mutex); + return ret; +} + +/** + * @brief The lseek method is used to change the current read/write position + * in a file + * + * @param [in] fp File pointer points to the file descriptor. + * @param [in] offset Offset. + * @param [in] origin Origin. + * + * @return On success The new position(resulting offset) is returned. + * On failure Returns negative error number. + */ +loff_t eep_lseek(struct file *fp, loff_t offset, int origin) +{ + loff_t current_offset = 0; + + eep_log("lseek.\n"); + + mutex_lock(&eep_mutex); + + switch (origin) { + case SEEK_SET: + current_offset = offset; + break; + case SEEK_CUR: + current_offset = fp->f_pos + offset; + break; + case SEEK_END: + current_offset = eeprom_size - offset; + break; + default: + break; + } + if (current_offset >= eeprom_size) { + eep_err("offset overflow!\n"); + current_offset = eeprom_size - 1; + } else if (current_offset < 0) { + eep_err("offset underflow!\n"); + current_offset = 0; + } + + fp->f_pos = current_offset; + + mutex_unlock(&eep_mutex); + return current_offset; +} + +/** + * @brief This function reads the data from eeprom device. + * + * @param [in] fp File pointer points to the file descriptor. + * @param [in] buf Pointer to the user space buffer. + * @param [in] count Number of bytes application intend to read. + * @param [in/out] pos Current file offset position. + * + * @return On success Returns count(number of read bytes). + * On failure Returns negative error number. + */ +ssize_t eep_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) +{ + int ret = 0; + + mutex_lock(&eep_mutex); + ret = eeprom_usr_read(buf, count, fp->f_pos); + if (ret < 0) { + eep_warn("eep_read failed. ret: %d", ret); + } + mutex_unlock(&eep_mutex); + + return ret; +} + +/** + * @brief This function writes the data to eeprom device. + * + * @param [in] fp File pointer points to the file descriptor. + * @param [in] buf Pointer to the user space buffer. + * @param [in] count Number of bytes application intend to write. + * @param [in/out] pos Current file offset position. + * + * @return On success Returns count(the number of bytes successfully written). + * On failure Returns negative error number. + */ +ssize_t eep_write(struct file *fp, const char __user *buf, + size_t count, loff_t *pos) +{ + int ret = 0; + + mutex_lock(&eep_mutex); + ret = eeprom_usr_write(buf, count, fp->f_pos); + if (ret < 0) { + eep_warn("eep_write failed. ret: %d", ret); + } + mutex_unlock(&eep_mutex); + + return ret; +} + + +/** + * @brief This function performs control operations on eeprom. + * + * @param [in] fp File pointer points to the file descriptor. + * @param [in] cmd Request command. + * @param [in/out] args The arguments based on request command. + * + * @return On Success Returns zero. + * On failure Returns negative error number. + */ +long eep_ioctl(struct file *fp, unsigned int cmd, unsigned long args) +{ + int protect = 0, size; + long ret = 0; + + eep_log("ioctl.\n"); + + /*verify args*/ + if (_IOC_TYPE(cmd) != EEPROM_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > EEPROM_MAX_CMDS) + return -ENOTTY; + if (_IOC_DIR(cmd) & _IOC_READ) + if (!access_ok(VERIFY_WRITE, (void *)args, _IOC_SIZE(cmd))) + return -EFAULT; + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (!access_ok(VERIFY_READ, (void *)args, _IOC_SIZE(cmd))) + return -EFAULT; + mutex_lock(&eep_mutex); + switch (cmd) { + case EEPROM_RESET: + eep_reset(); + break; + case EEPROM_SET_WP: + if (copy_from_user(&protect, (int *)args, sizeof(int))) { + eep_warn("failed copy_from_user.\n"); + return -EFAULT; + } + eep_set_wp(protect); + break; + case EEPROM_GET_WP: + protect = eep_get_wp(); + if (copy_to_user((int *)args, &protect, sizeof(int))) { + eep_warn("failed copy_to_user.\n"); + ret = -EFAULT; + } + break; + case EEPROM_GET_SIZE: + size = eeprom_size; + if (copy_to_user((int *)args, &size, sizeof(int))) { + eep_warn("failed copy_to_user.\n"); + ret = -EFAULT; + } + break; + case EEPROM_WRITE_DATA: + case EEPROM_READ_DATA: + { + struct eeprom_io_pkt *pkt = (struct eeprom_io_pkt *)args; + if (cmd == EEPROM_WRITE_DATA) + ret = eeprom_usr_write(pkt->wbuf, pkt->size, pkt->addr); + else + ret = eeprom_usr_read(pkt->rbuf, pkt->size, pkt->addr); + if (ret < 0) { + eep_warn("failed handle eeprom data: %ld", ret); + } + } + break; + default: + eep_warn("invalid cmd %d \n", cmd); + ret = -EFAULT; + break; + } + mutex_unlock(&eep_mutex); + return ret; +} + +/** + * @brief This function will be called when the user read from sysfs. + * + * @param [in] dev device. + * @param [in] attr device attributes. + * @param [in/out] buf buffer. + * + * @return On success Returns maxlen characters pointed to by buf. + * On failure Returns negative error number. + */ +static ssize_t nvram_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + eep_log("called.\n"); + + mutex_lock(&eep_mutex); + snprintf(buf, sizeof(int), "%d", eeprom_size); + mutex_unlock(&eep_mutex); + return strnlen(buf, MAX_ATTR_BYTES); +} + +/* for using sysfs. (class, device, device attribute) */ +static struct class *eep_class; +static struct device *eep_dev; +static DEVICE_ATTR_RO(nvram_size); + +static const struct of_device_id eepdev_of_match[] = { + { .compatible = "sii,s24c512c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, eepdev_of_match); + +/** + * Devices are identified using device id + * of the chip + */ +static const struct i2c_device_id eep_i2c_id[] = { + { "s24c512c", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, eep_i2c_id); + +/* device number */ +dev_t eeprom_dev_num; + +/* function pointers for file operations */ +static const struct file_operations eep_drv_fops = { + .llseek = eep_lseek, + .read = eep_read, + .open = eep_open, + .release = eep_close, + .write = eep_write, + .unlocked_ioctl = eep_ioctl, + .owner = THIS_MODULE, +}; + + +/* Device initialization routine */ +static int __init eep_init(void) +{ + int res = 0; + + eep_info("init!!\n"); + + counter = 0; + eeprom_dev_major = 0; + eeprom_dev_num = 0; + eep_dev = NULL; + eep_class = NULL; + //eep_client = NULL; + + /* register device with file operation mappings + * for dynamic allocation of major number + */ + res = register_chrdev(eeprom_dev_major, EEPROM_DEV_NAME, &eep_drv_fops); + if (res < 0) { + eep_err("failed to get major number.\n"); + goto out; + } + /* if the allocation is dynamic ?*/ + if (res != 0) + eeprom_dev_major = res; + + eeprom_dev_num = MKDEV(eeprom_dev_major, 0); + + /* create class. (/sys/class/eep_class) */ + eep_class = class_create(THIS_MODULE, "eep_class"); + if (IS_ERR(eep_class)) { + res = PTR_ERR(eep_class); + goto out_unreg_chrdev; + } + /* create class device. (/sys/class/eep_class/eeprom) */ + eep_dev = device_create(eep_class, NULL, eeprom_dev_num, NULL, + "eeprom"); + + if (IS_ERR(eep_dev)) { + res = PTR_ERR(eep_dev); + goto out_unreg_class; + } + /* create sysfs file. (/sys/class/eep_class/eeprom/nvram_size) */ + res = device_create_file(eep_dev, &dev_attr_nvram_size); + if (res) { + eep_err("failed to create sysfs.\n"); + goto out_unreg_device; + } + + return res; + + //out_unreg_sysfs: + // device_remove_file(eep_dev, &dev_attr_nvram_size); +out_unreg_device: + device_destroy(eep_class, eeprom_dev_num); +out_unreg_class: + class_destroy(eep_class); +out_unreg_chrdev: + unregister_chrdev(eeprom_dev_major, EEPROM_DEV_NAME); +out: + return res; +} + +/* Device exit routine */ +static void __exit eep_exit(void) +{ + eep_info("Exit!!\n"); + + /* remove sysfs file */ + device_remove_file(eep_dev, &dev_attr_nvram_size); + /* remove class device */ + device_destroy(eep_class, eeprom_dev_num); + /* remove class */ + class_destroy(eep_class); + //i2c_del_driver(&eep_i2c_driver); + /* unregister device */ + unregister_chrdev(eeprom_dev_major, EEPROM_DEV_NAME); + + /* for emulator */ +} + +/* define module init/exit, license */ +subsys_initcall(eep_init); +module_exit(eep_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dronamraju Santosh Pavan Kumar, <dronamraj.k@samsung.com>"); diff --git a/drivers/maru/maru_eeprom.h b/drivers/maru/maru_eeprom.h new file mode 100644 index 000000000000..6d750f65d652 --- /dev/null +++ b/drivers/maru/maru_eeprom.h @@ -0,0 +1,61 @@ +/** + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. + * Copyright (C) 2013 Samsung R&D Institute India-Delhi. + * Author: Dronamraju Santosh Pavan Kumar <dronamraj.k@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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. + * + * @file eeprom.h + * @brief Header file for the eeprom_s24c512c eeprom chip. + * @author Dronamraju Santosh pavan Kumar <dronamraj.k@samsung.com> + * @date 2013/07/12 + * + */ + +/* internal Release1 */ + +#ifndef _EEPROM_H +#define _EEPROM_H + +#include<asm-generic/ioctl.h> + +#define EEPROM_MAGIC 'I' +#define EEPROM_LOCAL_BUFF_SIZE 128 + +/*device name*/ +#define EEPROM_DEV_NAME "eeprom" + +struct eeprom_io_pkt { + unsigned int addr; + unsigned int size; + const char *wbuf; + char *rbuf; +}; + +#define EEPROM_RESET _IOW(EEPROM_MAGIC, 0x01, int) +#define EEPROM_SET_WP _IOW(EEPROM_MAGIC, 0x02, int) +#define EEPROM_GET_WP _IOR(EEPROM_MAGIC, 0x03, int) +#define EEPROM_GET_SIZE _IOR(EEPROM_MAGIC, 0x04, int) +#define EEPROM_WRITE_DATA _IOW(EEPROM_MAGIC, 0x05, struct eeprom_io_pkt *) +#define EEPROM_READ_DATA _IOR(EEPROM_MAGIC, 0x06, struct eeprom_io_pkt *) +#define EEPROM_SLAVE_ADDR 0x50 +#define EEPROM_MAX_CMDS 6 + +/* function prototypes */ +int eep_i2c_write(unsigned int addr, const unsigned char *buf, int len); +int eep_reg_write(unsigned int reg, const unsigned char *buf, int len); +int eep_reg_read(unsigned int reg, unsigned char *buf, int len); +int eep_set_wp(int protect); +int eep_get_wp(void); +ssize_t eeprom_dev_write(char *buf, size_t count, unsigned long addr); +ssize_t eeprom_dev_read(char *buf, size_t count, unsigned long addr); + +#endif /*_EEPROM_H */ diff --git a/drivers/maru/tztv-dummy/Makefile b/drivers/maru/tztv-dummy/Makefile new file mode 100644 index 000000000000..32e9052f8835 --- /dev/null +++ b/drivers/maru/tztv-dummy/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_MARU_DUMMY) += maru_dummy.o +obj-$(CONFIG_MARU_SECURITY) += maru_dummy_security.o +obj-$(CONFIG_MARU_SDP_MEM) += maru_dummy_sdp_mem.o +obj-$(CONFIG_MARU_GPIO) += maru_dummy_gpio.o +obj-$(CONFIG_MARU_I2C_SDP) += maru_dummy_i2c_sdp.o +obj-$(CONFIG_MARU_MICOM_MSG) += maru_dummy_micom_msg.o +obj-$(CONFIG_MARU_MICOM_ISP) += maru_dummy_micom_isp.o
\ No newline at end of file diff --git a/drivers/maru/tztv-dummy/maru_dummy.c b/drivers/maru/tztv-dummy/maru_dummy.c new file mode 100644 index 000000000000..725490e65e4a --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy.c @@ -0,0 +1,219 @@ +/* + * MARU dummy driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi <jinh0.choi@samsung.com> + * Hyunjin Lee <hyunjin816.lee@samsung.com> + * SangHo Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/cdev.h> + +#include <linux/mm.h> +#include <linux/mm_types.h> + +#include "maru_dummy.h" + +struct dummy_device { + const char *name; + struct class *dev_class; + struct device* dev_device; + struct cdev cdev; + dev_t dev; + struct file_operations fops; +}; + +static DECLARE_WAIT_QUEUE_HEAD(wq); + +int dummy_driver_debug = 0; +module_param(dummy_driver_debug, int, 0644); +MODULE_PARM_DESC(dummy_driver_debug, "Turn on/off maru dummy debugging (default:off)."); + +#define GENERATE_ACCESSORS_DEV(_dev) \ +static int maru_##_dev##_open(struct inode *inode, struct file *file) \ +{ \ + maru_device_dbg(1, "open is called.\n"); \ + return 0; \ +} \ +static int maru_##_dev##_close(struct inode *inode, struct file *file) \ +{ \ + maru_device_dbg(1, "close is called.\n"); \ + return 0; \ +} \ +static long maru_##_dev##_ioctl(struct file *file, unsigned int cmd, unsigned long arg) \ +{ \ + maru_device_dbg(1, "ioctl cmd : 0x%08x, arg : 0x%08lx\n", cmd, arg); \ + return 0; \ +} \ +static ssize_t maru_##_dev##_write(struct file *file, const char __user *buf, \ + size_t len, loff_t *ppos) \ +{ \ + maru_device_dbg(1, "write is called. size: %d, buf: %s, \n", len, buf); \ + return len; \ +} \ +static unsigned int maru_##_dev##_poll(struct file *file, struct poll_table_struct *wait) \ +{ \ + return 0; \ +} + +#define __ATTRIBUTE_DUMMY_DEVICE(_name) { \ + .name = __stringify(_name), \ + .fops = { \ + .open = maru_##_name##_open, \ + .unlocked_ioctl = maru_##_name##_ioctl, \ + .write = maru_##_name##_write, \ + .poll = maru_##_name##_poll, \ + .release = maru_##_name##_close \ + }, \ +} + +#define __ATTRIBUTE_HYPHEN_DUMMY_DEVICE(_name, _fname) {\ + .name = __stringify(_name), \ + .fops = { \ + .open = maru_##_fname##_open, \ + .unlocked_ioctl = maru_##_fname##_ioctl,\ + .write = maru_##_fname##_write, \ + .poll = maru_##_fname##_poll, \ + .release = maru_##_fname##_close \ + }, \ +} + +GENERATE_ACCESSORS_DEV(tztv_frc) +GENERATE_ACCESSORS_DEV(tztv_tcon) +GENERATE_ACCESSORS_DEV(micom_cec) +GENERATE_ACCESSORS_DEV(micom_ar) +GENERATE_ACCESSORS_DEV(micom_bsensor) +GENERATE_ACCESSORS_DEV(kfactory) + +struct dummy_device dummy_device_group[] = { + __ATTRIBUTE_DUMMY_DEVICE(tztv_frc), + __ATTRIBUTE_DUMMY_DEVICE(tztv_tcon), + __ATTRIBUTE_HYPHEN_DUMMY_DEVICE(micom-cec, micom_cec), + __ATTRIBUTE_HYPHEN_DUMMY_DEVICE(micom-ar, micom_ar), + __ATTRIBUTE_HYPHEN_DUMMY_DEVICE(micom-bsensor, micom_bsensor), + __ATTRIBUTE_DUMMY_DEVICE(kfactory), +}; + +static void remove_device(struct dummy_device *device) +{ + if (device == NULL) { + return; + } + + if (device->dev_device) { + device_destroy(device->dev_class, device->dev); + device->dev_device = NULL; + } + + if (device->dev) { + unregister_chrdev_region(device->dev, 1); + } + + if (device->dev_class) { + class_destroy(device->dev_class); + } +} + +static int create_device(struct dummy_device *device) +{ + int ret = 0; + + if (device == NULL) { + maru_device_err("failed to create device: device == NULL \n"); + return ret; + } + + ret = alloc_chrdev_region(&device->dev, 0, 1, device->name); + if (ret < 0) { + maru_device_err("%s alloc_chrdev_region failed.\n", device->name); + return ret; + } + + device->dev_class = class_create(THIS_MODULE, device->name); + if (IS_ERR(device->dev_class)) { + ret = PTR_ERR(device->dev_class); + maru_device_err("create %s class failed.\n", device->name); + remove_device(device); + return ret; + } + + cdev_init(&device->cdev, &device->fops); + + ret = cdev_add(&device->cdev, device->dev, 1); + if (ret < 0) { + maru_device_err("%s cdev_add failed\n", device->name); + remove_device(device); + return ret; + } + + device->dev_device = device_create(device->dev_class, 0, device->dev, NULL, "%s", device->name); + if (ret < 0) { + maru_device_err("%s device_create failed\n", device->name); + remove_device(device); + return ret; + } + + return 0; +} + +static int __init maru_dummy_init(void) +{ + int ret = 0; + int i = 0; + int size = sizeof(dummy_device_group) / sizeof(dummy_device_group[0]); + + for (i = 0; i < size; i++) { + ret = create_device(&dummy_device_group[i]); + if (ret < 0) + continue; + } + + maru_device_info("dummy driver was initialized.\n"); + + return 0; +} + +static void __exit maru_dummy_exit(void) +{ + int i = 0; + int size = sizeof(dummy_device_group) / sizeof(dummy_device_group[0]); + + for (i = 0; i < size; i++) { + remove_device(&dummy_device_group[i]); + } + + maru_device_info("dummy driver was exited.\n"); +} + +module_init(maru_dummy_init); +module_exit(maru_dummy_exit);
\ No newline at end of file diff --git a/drivers/maru/tztv-dummy/maru_dummy.h b/drivers/maru/tztv-dummy/maru_dummy.h new file mode 100644 index 000000000000..c61154dcb39a --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy.h @@ -0,0 +1,52 @@ +/* + * MARU dummy driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi <jinh0.choi@samsung.com> + * Hyunjin Lee <hyunjin816.lee@samsung.com> + * SangHo Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#ifndef _MARU_DUMMY_H +#define _MARU_DUMMY_H + +extern int dummy_driver_debug; + +#define maru_device_err(fmt, arg...) \ + printk(KERN_ERR "[ERR][%s]: " fmt, __func__, ##arg) + +#define maru_device_warn(fmt, arg...) \ + printk(KERN_WARNING "[WARN][%s]: " fmt, __func__, ##arg) + +#define maru_device_info(fmt, arg...) \ + printk(KERN_INFO "[INFO][%s]: " fmt, __func__, ##arg) + +#define maru_device_dbg(log_level, fmt, arg...) \ + do { \ + if (dummy_driver_debug >= (log_level)) { \ + printk(KERN_INFO "[DEBUG][%s]: " fmt, __func__, ##arg); \ + } \ + } while (0) + +#endif
\ No newline at end of file diff --git a/drivers/maru/tztv-dummy/maru_dummy_gpio.c b/drivers/maru/tztv-dummy/maru_dummy_gpio.c new file mode 100644 index 000000000000..da39881e5f86 --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_gpio.c @@ -0,0 +1,196 @@ +/* + * MARU Dummy GPIO driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi <jinh0.choi@samsung.com> + * SangHo Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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 License13 + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/platform_device.h> + +#include "maru_dummy.h" + +#define DRVNAME "maru_gpio" + +struct maru_gpio_dev { + int addr; +}; + +struct maru_gpio { + struct gpio_chip chip; + struct maru_gpio_dev *dev; +}; + +static int maru_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + maru_device_dbg(1, "gpio request offset : %u\n", offset); + return 0; +} + +static int maru_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + maru_device_dbg(1, "gpio direction in offset : %u\n", offset); + return 0; +} + +static int maru_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + maru_device_dbg(1, "gpio direction out offset : %u, value : %d\n", offset, value); + return 0; +} + +static int maru_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + maru_device_dbg(1, "gpio get offset : %u\n", offset); + return 0; +} + +static void maru_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + maru_device_dbg(1, "gpio set offset : %u, value : %d\n", offset, value); +} + +static int maru_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + maru_device_dbg(1, "gpio to irq offset : %u\n", offset); + return 0; +} + +static struct gpio_chip maru_gpio_chip = { + .label = DRVNAME, + .owner = THIS_MODULE, + .request = maru_gpio_request, + .direction_input = maru_gpio_direction_in, + .direction_output = maru_gpio_direction_out, + .get = maru_gpio_get, + .set = maru_gpio_set, + .to_irq = maru_gpio_to_irq, + .can_sleep = 1, + .ngpio = 255, + .base = 1, +}; + +static int maru_gpio_probe(struct platform_device *pdev) +{ + struct maru_gpio *maru_gpio; + int ret; + + maru_gpio = devm_kzalloc(&pdev->dev, sizeof(*maru_gpio), + GFP_KERNEL); + if (maru_gpio == NULL){ + maru_device_err("Could not allocate maru_gpio\n"); + return -ENOMEM; + } + + maru_gpio->chip = maru_gpio_chip; + maru_gpio->chip.dev = &pdev->dev; + + ret = gpiochip_add(&maru_gpio->chip); + if (ret < 0) { + maru_device_err("Could not register maru gpiochip %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, maru_gpio); + + maru_device_info("maru gpio device probe done.\n"); + + return ret; +} + +void maru_gpio_remove(struct platform_device *pdev) +{ + struct maru_gpio *maru_gpio = platform_get_drvdata(pdev); + + gpiochip_remove(&maru_gpio->chip); +} + +static struct platform_device *maru_gpio_pdev; + +static int __init maru_gpio_device_add(const struct maru_gpio_dev *dev) +{ + int err; + + maru_gpio_pdev = platform_device_alloc(DRVNAME, -1); + if (!maru_gpio_pdev) + return -ENOMEM; + + err = platform_device_add_data(maru_gpio_pdev, dev, sizeof(*dev)); + if (err) { + maru_device_err("Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(maru_gpio_pdev); + if (err) { + maru_device_err("Device addition failed\n"); + goto err; + } + + maru_device_info("maru_gpio_device is added.\n"); + return 0; +err: + platform_device_put(maru_gpio_pdev); + + return err; +} + +static struct platform_driver maru_gpio_driver = { + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, + .probe = maru_gpio_probe, + .remove = maru_gpio_remove, +}; + +static int __init maru_gpio_init(void) +{ + int err; + struct maru_gpio_dev dev; + + err = platform_driver_register(&maru_gpio_driver); + if (!err) { + err = maru_gpio_device_add(&dev); + if (err) + platform_driver_unregister(&maru_gpio_driver); + } + + return err; +} +subsys_initcall(maru_gpio_init); + +static void __exit maru_gpio_exit(void) +{ + platform_driver_unregister(&maru_gpio_driver); +} +module_exit(maru_gpio_exit); + +MODULE_AUTHOR("Jinhyung Choi"); +MODULE_DESCRIPTION("Maru Dummy GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/maru/tztv-dummy/maru_dummy_i2c_sdp.c b/drivers/maru/tztv-dummy/maru_dummy_i2c_sdp.c new file mode 100644 index 000000000000..810b76999c0e --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_i2c_sdp.c @@ -0,0 +1,278 @@ +/* + * MARU Dummy I2C SDP driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Jinhyung Choi <jinh0.choi@samsung.com> + * SangHo Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/io.h> + +#include <asm/irq.h> +#include <linux/semaphore.h> + +#include "maru_dummy.h" + +/* i2c controller state */ +enum sdp_i2c_state { + STATE_IDLE, + STATE_START, + STATE_READ, + STATE_WRITE, + STATE_STOP +}; + +struct sdp_platform_i2c { + int bus_num; + unsigned int flags; + unsigned int slave_addr; + unsigned long frequency; + unsigned int sda_delay; + unsigned int irq_reg; +}; + +struct sdp_i2c { + wait_queue_head_t wait; + + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_idx; + unsigned int msg_ptr; + + unsigned int tx_setup; + unsigned int irq; + + enum sdp_i2c_state state; + unsigned long clkrate; + + void __iomem *regs; + void __iomem *irq_reg; + struct clk *clk; + struct device *dev; + struct i2c_adapter adap; + + struct sdp_platform_i2c *pdata; + +}; + +static spinlock_t lock_pend; +static spinlock_t lock_int; + +static int sdp_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + maru_device_dbg(1, "sdp_i2c_xfer"); + return 0; +} + +static u32 sdp_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | + I2C_FUNC_PROTOCOL_MANGLING; +} + +static const struct i2c_algorithm sdp_i2c_algorithm = { + .master_xfer = sdp_i2c_xfer, + .functionality = sdp_i2c_func, +}; + +static int sdp_i2c_get_irq_reg(struct sdp_i2c *i2c) +{ + struct sdp_platform_i2c *pdata; + pdata = i2c->pdata; + + i2c->irq_reg = ioremap(pdata->irq_reg, 8); + + if (!i2c->irq_reg) { + maru_device_err("Can't get interrupts status register\n"); + return -ENXIO; + } + + return 0; +} + +static int sdp_i2c_probe(struct platform_device *pdev) +{ + struct sdp_i2c *i2c; + struct sdp_platform_i2c *pdata = NULL; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(struct sdp_i2c), GFP_KERNEL); + if (!i2c) { + maru_device_err("no memory for state\n"); + return -ENOMEM; + } + + i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!i2c->pdata) { + ret = -ENOMEM; + goto err_noclk; + } + + spin_lock_init(&lock_pend); + spin_lock_init(&lock_int); + + strlcpy(i2c->adap.name, "sdp-i2c", sizeof(i2c->adap.name)); + i2c->adap.owner = THIS_MODULE; + i2c->adap.algo = &sdp_i2c_algorithm; + i2c->adap.retries = 2; + i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + i2c->tx_setup = 50; + + init_waitqueue_head(&i2c->wait); + + i2c->dev = &pdev->dev; + i2c->clk = clk_get(&pdev->dev, "rstn_i2c"); + if (IS_ERR(i2c->clk)) { + maru_device_err("cannot get clock\n"); + ret = -ENOENT; + goto err_noclk; + } + + clk_prepare_enable(i2c->clk); + + i2c->adap.algo_data = i2c; + i2c->adap.dev.parent = &pdev->dev; + + ret = sdp_i2c_get_irq_reg(i2c); + if (ret != 0) + goto err_clk; + + i2c->adap.nr = 6; + ret = i2c_add_numbered_adapter(&i2c->adap); + if (ret < 0) { + maru_device_err("failed to add bus to i2c core\n"); + goto err_irq; + } + + platform_set_drvdata(pdev, i2c); + + return 0; + + err_irq: + free_irq(i2c->irq, i2c); + + err_clk: + clk_disable_unprepare(i2c->clk); + clk_put(i2c->clk); + + err_noclk: + return ret; +} + +static int sdp_i2c_remove(struct platform_device *pdev) +{ + struct sdp_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + free_irq(i2c->irq, i2c); + + clk_disable_unprepare(i2c->clk); + clk_put(i2c->clk); + + return 0; +} + +static struct platform_driver sdp_i2c_driver = { + .probe = sdp_i2c_probe, + .remove = sdp_i2c_remove, + .driver = { + .name = "sdp-i2c", + .owner = THIS_MODULE, + }, +}; + +struct maru_i2c_dev { + int addr; +}; + +static struct platform_device *maru_i2c_pdev; + +static int __init maru_i2c_device_add(const struct maru_i2c_dev *dev) +{ + int err; + + maru_i2c_pdev = platform_device_alloc("sdp-i2c", -1); + if (!maru_i2c_pdev) + return -ENOMEM; + + err = platform_device_add_data(maru_i2c_pdev, dev, sizeof(*dev)); + if (err) { + maru_device_err("Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(maru_i2c_pdev); + if (err) { + maru_device_err("Device addition failed\n"); + goto err; + } + + maru_device_info("maru_i2c_device is added.\n"); + return 0; +err: + platform_device_put(maru_i2c_pdev); + + return err; +} + +static int __init sdp_i2c_init(void) +{ + int err; + + struct maru_i2c_dev dev; + + err = platform_driver_register(&sdp_i2c_driver); + if (!err) { + err = maru_i2c_device_add(&dev); + if (err) + platform_driver_unregister(&sdp_i2c_driver); + } + + return err; +} +subsys_initcall(sdp_i2c_init); + +static void __exit sdp_i2c_exit(void) +{ + platform_driver_unregister(&sdp_i2c_driver); +} +module_exit(sdp_i2c_exit); + +MODULE_AUTHOR("Jinhyung Choi"); +MODULE_DESCRIPTION("Maru Dummy I2C SDP driver"); +MODULE_LICENSE("GPL");
\ No newline at end of file diff --git a/drivers/maru/tztv-dummy/maru_dummy_micom_isp.c b/drivers/maru/tztv-dummy/maru_dummy_micom_isp.c new file mode 100644 index 000000000000..f12df2c7a905 --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_micom_isp.c @@ -0,0 +1,269 @@ +/* + * MARU MICOM ISP + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Dongkyun Yun <dk77.yun@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/cdev.h> + +#define DRIVER_NAME "isp-wt61p807" +#define DEV_NAME "micom-isp" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off maru micom isp debugging (default:off)."); + +#define print_err(fmt, arg...) \ + printk(KERN_ERR "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_warn(fmt, arg...) \ + printk(KERN_WARNING "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_info(fmt, arg...) \ + printk(KERN_INFO "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_dbg(level, fmt, arg...) \ + do { \ + if (debug >= (level)) { \ + printk(KERN_INFO "[%s](%s:%d)[%s:%d]: " fmt, DEV_NAME, \ + __func__, __LINE__, current->comm, current->pid, ##arg); \ + } \ + } while (0) + +/* contains device information */ +struct wt61p807_isp_data { + struct cdev *isp_dev; + struct class *isp_class; + struct device *isp_device; + int micom_isp_major; + int ref_count; +}; + +struct wt61p807_isp_data *wt61p807_isp; + +/* static mutexes for micom isp driver */ +DEFINE_MUTEX(isp_dev_lock); + +/* global structures for wt61p807_isp_data and wt61p807_isp_cdev as those must + * be accessible from other functions ie.open, release etc. + */ +struct wt61p807_isp_data m_isp_dev; +static struct cdev wt61p807_isp_cdev; + +/* micom isp file operations */ +static int micom_isp_open(struct inode *inode, struct file *filp); +static int micom_isp_release(struct inode *inode, struct file *filp); +static long micom_isp_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); + +/* file operations for micom isp device */ +const struct file_operations wt61p807_isp_fops = { + .owner = THIS_MODULE, + .open = micom_isp_open, + .unlocked_ioctl = micom_isp_ioctl, + .release = micom_isp_release, +}; + +/* + * + * @fn static int micom_isp_open(struct inode *inode, \ + * struct file *filp); + * @brief opens micom isp device and returns file descriptor + * @details opens micom isp device and increments m_isp_dev_p->ref_count by + * one. + * + * @param inode pointer to device node's inode structure + * filp pointer to device node file + * + * @return returns file descriptor if device is opened successfully + */ +static int micom_isp_open(struct inode *inode, struct file *filp) +{ + struct wt61p807_isp_data *wt61p807_isp = &m_isp_dev; + + /* acquire lock before setting is_open.*/ + mutex_lock(&isp_dev_lock); + + wt61p807_isp->ref_count++; + print_dbg(1, "reference count : %d\n", wt61p807_isp->ref_count); + + /* Release lock*/ + mutex_unlock(&isp_dev_lock); + + return 0; +} + +/* @fn static long micom_isp_ioctl(struct file *filp, \ + * unsigned int cmd, unsigned long arg); + * @brief handles IOCTLs addressed to micom isp device and returns status + * @details valid IOCTLs: + * MICOM_MSG_IOCTL_SEND_MSG: Used to send messages + * containing normal data to micom device. It expects + * acknowledgement from the device. + * MICOM_MSG_IOCTL_SEND_MSG_NO_ACK: Used to send messages + * containing normal buffer data without expecting any + * acknowledgement from micom isp device. + * + * @param filp pointer to device node file + * cmd IOCTL command. + * arg argument to ioctl command (struct sdp_micom_usr_isp). + * + * @return returns status of IOCTL + * -EINVAL: if null arg is passed from user. + * -EFAULT: if copy_from_user() fails to copy + * -ERANGE: if micom command sent from user exceeds the + * defined max value (0xFF) + * zero: if suceess + */ +static long micom_isp_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + long status = 0; + + print_dbg(1, "device ioctl \n"); + + return status; +} + +/* + * + * @fn static int micom_isp_release(struct inode *inode, \ + * struct file *filp); + * @brief closes micom isp device and returns status + * @details + * + * @param inode pointer to device node's inode structure + * filp pointer to device node file + * + * @return returns zero if device is closed + */ +static int micom_isp_release(struct inode *inode, struct file *filp) +{ + + struct wt61p807_isp_data *wt61p807_isp = &m_isp_dev; + + /* acquire lock before setting is_open.*/ + mutex_lock(&isp_dev_lock); + + wt61p807_isp->ref_count--; + print_dbg(1 , "reference count : %d\n", wt61p807_isp->ref_count); + + /* Release lock*/ + mutex_unlock(&isp_dev_lock); + + return 0; +} + +/* Device initialization routine */ +static int __init micom_isp_init(void) +{ + dev_t devid = 0; + int ret = -1; + + print_info("called \n"); + + /* allocate char device region */ + ret = alloc_chrdev_region(&devid, 0, 1, DRIVER_NAME); + if (ret) { + print_err("alloc_chrdev_region failed with %d\n", ret); + goto chrdev_alloc_fail; + } + + /* initialize associated cdev and attach the file_operations */ + cdev_init(&wt61p807_isp_cdev, &wt61p807_isp_fops); + /* add cdev to device */ + ret = cdev_add(&wt61p807_isp_cdev, devid, 1); + if (ret) { + print_err("cdev_add failed with %d\n", ret); + goto cdev_add_fail; + } + + wt61p807_isp = &m_isp_dev; + + wt61p807_isp->isp_dev = &wt61p807_isp_cdev; + wt61p807_isp->micom_isp_major = MAJOR(devid); + wt61p807_isp->ref_count = 0; + + wt61p807_isp->isp_class = class_create(THIS_MODULE, DRIVER_NAME); + if (IS_ERR(wt61p807_isp->isp_class)) { + print_err("failed to create sys class\n"); + } else { + wt61p807_isp->isp_device = device_create( + wt61p807_isp->isp_class, + NULL, devid, NULL, DEV_NAME); + if (IS_ERR(wt61p807_isp->isp_device)) { + print_err("failed to create sys device\n"); + class_destroy(wt61p807_isp->isp_class); + } + } + + /* dynamic initialization of mutex for device */ + mutex_init(&isp_dev_lock); + + return ret; + + /* cleaning up due to failure. */ +cdev_add_fail: + unregister_chrdev_region(devid, 1); +chrdev_alloc_fail: + return ret; +} + +/* Device exit routine */ +static void __exit micom_isp_exit(void) +{ + print_info("called \n"); + + mutex_destroy(&isp_dev_lock); + + /* destroy micom isp sysfs device and class */ + if (wt61p807_isp->isp_device != NULL) { + device_destroy(wt61p807_isp->isp_class, + MKDEV(wt61p807_isp->micom_isp_major, 0)); + } + if (wt61p807_isp->isp_class != NULL) + class_destroy(wt61p807_isp->isp_class); + + unregister_chrdev_region(MKDEV(m_isp_dev.micom_isp_major, 0), 1); + return; +} + +/* define module init/exit, license */ +subsys_initcall(micom_isp_init); +module_exit(micom_isp_exit); + +MODULE_DESCRIPTION("Micom driver interface for ISP data"); +MODULE_AUTHOR("Abhishek Jaiswal <abhishek1.j@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/maru/tztv-dummy/maru_dummy_micom_msg.c b/drivers/maru/tztv-dummy/maru_dummy_micom_msg.c new file mode 100644 index 000000000000..a830e6232876 --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_micom_msg.c @@ -0,0 +1,356 @@ +/* + * MARU MICOM MSG + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Dongkyun Yun <dk77.yun@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +/* internal Release1 */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/poll.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/platform_device.h> + +#define DRIVER_NAME "msg-wt61p807" +#define DEV_NAME "micom-msg" + +static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off maru micom msg debugging (default:off)."); + +#define print_err(fmt, arg...) \ + printk(KERN_ERR "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_warn(fmt, arg...) \ + printk(KERN_WARNING "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_info(fmt, arg...) \ + printk(KERN_INFO "[%s](%s)[%s:%d]: " fmt, DEV_NAME, __func__, \ + current->comm, current->pid, ##arg); + +#define print_dbg(level, fmt, arg...) \ + do { \ + if (debug >= (level)) { \ + printk(KERN_INFO "[%s](%s:%d)[%s:%d]: " fmt, DEV_NAME, \ + __func__, __LINE__, current->comm, current->pid, ##arg); \ + } \ + } while (0) + +/* no of retries */ +#define ACK_RETRY_MAX 4 + +/* static mutexes for micom msg device */ +DEFINE_MUTEX(dev_msg_lock); + +/* list of micom msg file operations prototypes. */ +static int micom_msg_open(struct inode *inode, struct file *filp); +static int micom_msg_release(struct inode *inode, struct file *filp); +static long micom_msg_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); +static ssize_t show_jack_ident(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_scart_lv_1(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_scart_lv_2(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_jack_ident_ready(struct device *dev, + struct device_attribute *attr, char *buf); + +/* file operations for micom msg device */ +const struct file_operations wt61p807_msg_fops = { + .owner = THIS_MODULE, + .open = micom_msg_open, + .unlocked_ioctl = micom_msg_ioctl, + .release = micom_msg_release, +}; + +struct wt61p807_msg_data { + struct cdev *msg_dev; + struct class *msg_class; + struct device *msg_device; + int micom_msg_major; + int ref_count; + + int jack_ident; + int jack_ident_ready; + int scart_lv_1; + int scart_lv_2; +}; + +struct wt61p807_msg_data *wt61p807_msg; + +/* micom msg device specific data */ +struct wt61p807_msg_data m_msg_dev; + +/* micom msg cdev */ +struct cdev wt61p807_msg_cdev; + +static DEVICE_ATTR(jack_ident, S_IRUGO, show_jack_ident, NULL); +static DEVICE_ATTR(scart_lv_1, S_IRUGO, show_scart_lv_1, NULL); +static DEVICE_ATTR(scart_lv_2, S_IRUGO, show_scart_lv_2, NULL); +static DEVICE_ATTR(jack_ident_ready, S_IRUGO, + show_jack_ident_ready, NULL); + +/* + * + * @fn static int micom_msg_open(struct inode *inode, \ + * struct file *filp); + * @brief opens micom msg device and returns file descriptor + * @details opens micom msg device and increments m_msg_dev_p->ref_count. + * + * @param inode pointer to device node's inode structure + * filp pointer to device node file + * + * @return returns file descriptor if device is opened successfully + */ +static int micom_msg_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct wt61p807_msg_data *m_msg_dev_p = &m_msg_dev; + + /* acquire lock before opening device.*/ + mutex_lock(&dev_msg_lock); + + m_msg_dev_p->ref_count++; + + print_dbg(1, "MSG device is opened. ref_count[%d]\n", + m_msg_dev_p->ref_count); + + /* Release lock */ + mutex_unlock(&dev_msg_lock); + + return ret; +} + +/* + * + * @fn static int micom_msg_release(struct inode *inode, \ + * struct file *filp); + * @brief closes micom msg device and returns status + * @details + * + * @param inode pointer to device node's inode structure + * filp pointer to device node file + * + * @return returns zero if device is closed + */ +static int micom_msg_release(struct inode *inode, struct file *filp) +{ + + int ret = 0; + struct wt61p807_msg_data *m_msg_dev_p = &m_msg_dev; + + /* acquire lock before closing device.*/ + mutex_lock(&dev_msg_lock); + + m_msg_dev_p->ref_count--; + + print_dbg(1, "MSG device is closed. ref_count[%d]\n", + m_msg_dev_p->ref_count); + + /* Release lock*/ + mutex_unlock(&dev_msg_lock); + + return ret; +} + +/* + * + * @fn static long micom_msg_ioctl(struct file *filp, \ + * unsigned int cmd, unsigned long arg); + * @brief handles IOCTLs addressed to micom msg device and returns status + * @details valid IOCTLs: + * MICOM_MSG_IOCTL_SEND_MSG: Used to send messages + * containing normal data to micom device. It expects + * acknowledgement from the device. + * MICOM_MSG_IOCTL_SEND_MSG_NO_ACK: Used to send messages + * containing normal buffer data without expecting any + * acknowledgement from micom msg device. + * + * @param filp pointer to device node file + * cmd IOCTL command. + * arg argument to ioctl command (struct sdp_micom_usr_msg). + * + * @return returns status of IOCTL + * -EINVAL: if null arg is passed from user. + * -EFAULT: if copy_from_user() fails to copy + * -ERANGE: if micom command sent from user exceeds the + * defined max value (0xFF) + * zero: if suceess + */ +static long micom_msg_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + long status = 0; + + print_dbg(1, "MSG device ioctl \n"); + + return status; +} + +static ssize_t show_jack_ident(struct device *dev, + struct device_attribute *attr, char *buf) +{ + print_dbg(1, "\n"); + return snprintf(buf, sizeof(int), "%d", m_msg_dev.jack_ident); +} + +static ssize_t show_scart_lv_1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + print_dbg(1, "\n"); + return snprintf(buf, sizeof(int), "%d", m_msg_dev.scart_lv_1); +} + +static ssize_t show_scart_lv_2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + print_dbg(1, "\n"); + return snprintf(buf, sizeof(int), "%d", m_msg_dev.scart_lv_2); +} + +static ssize_t show_jack_ident_ready(struct device *dev, + struct device_attribute *attr, char *buf) +{ + print_dbg(1, "\n"); + return snprintf(buf, sizeof(int), "%d", m_msg_dev.jack_ident_ready); +} + +/* Device initialization routine */ +static int __init micom_msg_init(void) +{ + dev_t devid = 0; + int ret = -1; + + print_info("called \n"); + + /* allocate char device region */ + ret = alloc_chrdev_region(&devid, 0, 1, DRIVER_NAME); + if (ret) { + print_err("alloc_chrdev_region failed with %d\n", ret); + goto chrdev_alloc_fail; + } + + /* initialize associated cdev and attach the file_operations */ + cdev_init(&wt61p807_msg_cdev, &wt61p807_msg_fops); + /* add cdev to device */ + ret = cdev_add(&wt61p807_msg_cdev, devid, 1); + if (ret) { + print_err("cdev_add failed with %d\n", ret); + goto cdev_add_fail; + } + + wt61p807_msg = &m_msg_dev; + + wt61p807_msg->msg_dev = &wt61p807_msg_cdev; + wt61p807_msg->micom_msg_major = MAJOR(devid); + wt61p807_msg->ref_count = 0; + + wt61p807_msg->msg_class = class_create(THIS_MODULE, DEV_NAME); + if (IS_ERR(wt61p807_msg->msg_class)) { + print_err("failed to create sys class\n"); + } else { + wt61p807_msg->msg_device = device_create( + wt61p807_msg->msg_class, + NULL, devid, NULL, DEV_NAME); + if (IS_ERR(wt61p807_msg->msg_device)) { + print_err("failed to create sys device\n"); + class_destroy(wt61p807_msg->msg_class); + } + } + + ret = device_create_file(wt61p807_msg->msg_device, + &dev_attr_jack_ident); + if (ret) { + print_err("failed to create sysfs files (ret = %d) \n", ret); + goto dev_fail; + } + ret = device_create_file(wt61p807_msg->msg_device, + &dev_attr_scart_lv_1); + if (ret) { + print_err("failed to create sysfs files (ret = %d) \n", ret); + goto dev_fail; + } + ret = device_create_file(wt61p807_msg->msg_device, + &dev_attr_scart_lv_2); + if (ret) { + print_err("failed to create sysfs files (ret = %d) \n", ret); + goto dev_fail; + } + ret = device_create_file(wt61p807_msg->msg_device, + &dev_attr_jack_ident_ready); + if (ret) { + print_err("failed to create sysfs files (ret = %d) \n", ret); + goto dev_fail; + } + + /* dynamic initialization of mutex for device */ + mutex_init(&dev_msg_lock); + + return ret; + +dev_fail: +cdev_add_fail: + unregister_chrdev_region(devid, 1); +chrdev_alloc_fail: + return ret; +} + +/* Device exit routine */ +static void __exit micom_msg_exit(void) +{ + print_info("called \n"); + + mutex_destroy(&dev_msg_lock); + + /* destroy micom msg sysfs device and class */ + if (wt61p807_msg->msg_device != NULL) { + device_destroy(wt61p807_msg->msg_class, + MKDEV(wt61p807_msg->micom_msg_major, 0)); + } + if (wt61p807_msg->msg_class != NULL) + class_destroy(wt61p807_msg->msg_class); + + unregister_chrdev_region(MKDEV(wt61p807_msg->micom_msg_major, 0), 1); + return; +} + +/* define module init/exit, license */ +subsys_initcall(micom_msg_init); +module_exit(micom_msg_exit); + +MODULE_DESCRIPTION("Micom driver interface for Normal buffer data"); +MODULE_AUTHOR("Abhishek Jaiswal <abhishek1.j@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/maru/tztv-dummy/maru_dummy_sdp_mem.c b/drivers/maru/tztv-dummy/maru_dummy_sdp_mem.c new file mode 100644 index 000000000000..f9372b8c6d71 --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_sdp_mem.c @@ -0,0 +1,174 @@ +/* + * MARU SDP Memory Driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Dongkyun Yun <dk77.yun@samsung.com> + * Jinhyung Choi <jinh0.choi@samsung.com> + * Hyunjin Lee <hyunjin816.lee@samsung.com> + * SangHo Park <sangho.p@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ + +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/mm_types.h> +#include <linux/miscdevice.h> +#include <linux/vmalloc.h> + +#include "maru_dummy.h" + +#define DRV_NAME "sdp_mem" +#define SDP_MEM_MINOR 193 + +static LIST_HEAD(region_list); +static DEFINE_MUTEX(region_mutex); + +struct sdp_mem_region +{ + struct list_head list; + unsigned long vm_pgoff; + unsigned long size; + void *vaddr; +}; + +static int +sdp_mem_mmap(struct file * file, struct vm_area_struct * vma) +{ + int ret; + unsigned long size = vma->vm_end - vma->vm_start; + struct sdp_mem_region *region; + int pages; + + maru_device_dbg(1, "[%d:%s] \n", current->pid, current->comm); + + mutex_lock(®ion_mutex); + + list_for_each_entry(region, ®ion_list, list) { + if( region->vm_pgoff == vma->vm_pgoff ) { + if( region->size != size ) { + maru_device_err("size mismatch \n"); + /* TODO: use first mapping size */ + size = region->size; + } + maru_device_dbg(1, "pgoff %lx found \n", vma->vm_pgoff); + goto found; + } + } + + maru_device_dbg(1, "pgoff %lx not found \n", vma->vm_pgoff); + + region = kzalloc(sizeof(struct sdp_mem_region), GFP_KERNEL); + if (!region) { + maru_device_err("kzalloc fail \n"); + ret = -ENOMEM; + goto error; + } + + region->vm_pgoff = vma->vm_pgoff; + region->size = size; + + pages = PAGE_ALIGN(size); + region->vaddr = vmalloc_user(pages); + if (!region->vaddr) { + maru_device_err("vmalloc_user fail \n"); + kfree(region); + ret = -ENOMEM; + goto error; + } + list_add_tail(®ion->list, ®ion_list); + + maru_device_dbg(1, "vaddr(%p) with size(%lu) \n", region->vaddr, size); + +found: + + /* Try to remap memory */ + ret = remap_vmalloc_range(vma, region->vaddr, 0); + if (ret) { + maru_device_err("remap_vmalloc_range failed (ret:%d) \n", ret); + goto error; + } + + maru_device_info("%s/%d mmap phy addr(0x%lx, size:%lu) to 0x%p\n", + current->comm, current->pid, vma->vm_pgoff, size, region->vaddr); + +error: + mutex_unlock(®ion_mutex); + return ret; +} + +static int sdp_mem_open(struct inode *inode, struct file *file) +{ + maru_device_dbg(1, "open\n"); + return 0; +} + + +static int sdp_mem_close(struct inode *inode, struct file *file) +{ + maru_device_dbg(1, "close\n"); + return 0; +} + +static const struct file_operations sdp_mem_fops = { + .owner = THIS_MODULE, + .open = sdp_mem_open, + .release = sdp_mem_close, + .mmap = sdp_mem_mmap, +}; + +static struct miscdevice sdp_mem_dev = { + .minor = SDP_MEM_MINOR, + .name = DRV_NAME, + .fops = &sdp_mem_fops +}; + +static int __init maru_sdp_mem_init(void) +{ + int ret_val = 0; + + ret_val = misc_register(&sdp_mem_dev); + + if(ret_val){ + maru_device_err("misc_register is failed."); + return ret_val; + } + + maru_device_info("sdp_mem initialized."); + + return ret_val; +} + +static void __exit maru_sdp_mem_exit(void) +{ + misc_deregister(&sdp_mem_dev); +} + +module_init(maru_sdp_mem_init); +module_exit(maru_sdp_mem_exit); diff --git a/drivers/maru/tztv-dummy/maru_dummy_security.c b/drivers/maru/tztv-dummy/maru_dummy_security.c new file mode 100644 index 000000000000..59e9ee792e80 --- /dev/null +++ b/drivers/maru/tztv-dummy/maru_dummy_security.c @@ -0,0 +1,202 @@ +/* + * MARU security driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * Hyunjin Lee <hyunjin816.lee@samsung.com> + * SangHo Park <sangho1206.park@samsung.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; 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. + * + * Contributors: + * - S-Core Co., Ltd + * + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/mutex.h> +#include <linux/pagemap.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <linux/cdev.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <linux/interrupt.h> + +#define SECURITY_DEV_NAME "security" + +static unsigned security_debug = 0; +static struct class *security_class; +static struct cdev security_cdev; +dev_t security_dev; + +module_param(security_debug, int, 0644); +MODULE_PARM_DESC(security_debug, "Turn on/off maru security debugging (default:off)."); + +#define maru_security_err(fmt, arg...) \ + printk(KERN_ERR "[ERR]maru_security[%s]: " fmt, __func__, ##arg) + +#define maru_security_warn(fmt, arg...) \ + printk(KERN_WARNING "[WARN]maru_security[%s]: " fmt, __func__, ##arg) + +#define maru_security_info(fmt, arg...) \ + printk(KERN_INFO "[INFO]maru_security[%s]: " fmt, __func__, ##arg) + +#define maru_security_dbg(level, fmt, arg...) \ + do { \ + if (security_debug >= (level)) { \ + printk(KERN_ERR "[DBG]maru_security[%s]: " fmt, \ + __func__, ##arg); \ + } \ + } while (0) +#define SECURITY_G_SEQNUM _IOR('S', 0, unsigned int) + +struct security_information { + unsigned int seq_num; +}; + +/* ----------------------------------------------------------------- + file operations + ------------------------------------------------------------------*/ +static int maru_security_open(struct inode *inode, struct file *file) +{ + int ret = 0; + struct security_information *sec_info; + + maru_security_dbg(5, "[security]enter.\n"); + + sec_info = kzalloc(sizeof(struct security_information), GFP_KERNEL); + if (!sec_info) { + maru_security_err("kzalloc() failed\n"); + ret = -ENOMEM; + goto enomem; + } + + sec_info->seq_num = 0; + file->private_data = sec_info; + +enomem: + return ret; +} + +static long maru_security_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct security_information *sec_info = file->private_data; + int __user *data = (int __user *)arg; + + switch (cmd) { + case SECURITY_G_SEQNUM: + ret = copy_to_user(data, &sec_info->seq_num, sizeof(unsigned int)); + if (ret) { + ret = -EFAULT; + break; + } + sec_info->seq_num++; + break; + default: + maru_security_info("[security] unsupported command : %08x.\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static int maru_security_close(struct inode *inode, struct file *file) +{ + struct security_information *sec_info = file->private_data; + + maru_security_dbg(5, "[security]enter.\n"); + + if (sec_info) { + kfree(sec_info); + sec_info = NULL; + } + + return 0; +} + +static const struct file_operations maru_security_fops = { + .open = maru_security_open, + .unlocked_ioctl = maru_security_ioctl, + .release = maru_security_close, +}; + +/* ----------------------------------------------------------------- + Initialization + ------------------------------------------------------------------*/ +static int __init maru_security_init(void) +{ + int ret = 0; + + /* allocate character device */ + ret = alloc_chrdev_region(&security_dev, 0, 1, SECURITY_DEV_NAME); + if (ret < 0) { + maru_security_err("security alloc_chrdev_region failed.\n"); + goto alloc_chrdev_region_err; + } + + /* create class */ + security_class = class_create(THIS_MODULE, SECURITY_DEV_NAME); + if (IS_ERR(security_class)) { + ret = PTR_ERR(security_class); + maru_security_err("create security class failed.\n"); + goto create_class_err; + } + + /* character device initialize */ + cdev_init(&security_cdev, &maru_security_fops); + + ret = cdev_add(&security_cdev, security_dev, 1); + if (ret < 0) { + maru_security_err("security cdev_add failed\n"); + goto cdev_add_err; + } + + /* create device */ + device_create(security_class, 0, security_dev, NULL, "%s", SECURITY_DEV_NAME); + + maru_security_info("security driver was registerd.\n"); + + return ret; + +cdev_add_err: + class_destroy(security_class); +create_class_err: + unregister_chrdev_region(security_dev, 1); +alloc_chrdev_region_err: + return ret; +} + +static void __exit maru_security_exit(void) +{ + cdev_del(&security_cdev); + class_destroy(security_class); + unregister_chrdev_region(security_dev, 1); + + maru_security_info("security driver was exited.\n"); +} + +module_init(maru_security_init); +module_exit(maru_security_exit);
\ No newline at end of file |