From 9d43538162796100f16026a6ee26d826dd82320f Mon Sep 17 00:00:00 2001 From: wwd Date: Mon, 16 May 2016 13:20:02 +0800 Subject: [PATCH] matrix: support Matrix starter kit --- arch/arm/configs/sun8iw7p1smp_defconfig | 204 +++++++++++- arch/arm/mach-sunxi/sun8i.c | 55 ++++ drivers/char/Kconfig | 24 ++ drivers/char/Makefile | 5 + drivers/char/matrix_gpio_int.c | 309 +++++++++++++++++ drivers/char/matrix_hcsr04.c | 184 +++++++++++ drivers/char/matrix_pwm.c | 206 ++++++++++++ drivers/char/matrix_rotary_encoder.c | 205 ++++++++++++ drivers/input/misc/adxl34x.c | 33 +- drivers/staging/iio/Kconfig | 1 + drivers/staging/iio/Makefile | 1 + drivers/staging/iio/humidity/Kconfig | 15 + drivers/staging/iio/humidity/Makefile | 5 + drivers/staging/iio/humidity/dht11.c | 366 +++++++++++++++++++++ drivers/staging/iio/industrialio-core.c | 1 + drivers/staging/iio/types.h | 1 + drivers/w1/masters/Makefile | 2 +- drivers/w1/masters/w1-gpio-board.c | 59 ++++ drivers/w1/masters/w1-gpio.c | 13 +- .../sun8iw7p1/configs/nanopi-h3/sys_config.fex | 9 +- 21 files changed, 1684 insertions(+), 28 deletions(-) create mode 100644 drivers/char/matrix_gpio_int.c create mode 100644 drivers/char/matrix_hcsr04.c create mode 100644 drivers/char/matrix_pwm.c create mode 100644 drivers/char/matrix_rotary_encoder.c create mode 100644 drivers/staging/iio/humidity/Kconfig create mode 100644 drivers/staging/iio/humidity/Makefile create mode 100644 drivers/staging/iio/humidity/dht11.c create mode 100644 drivers/w1/masters/w1-gpio-board.c diff --git a/arch/arm/configs/sun8iw7p1smp_defconfig b/arch/arm/configs/sun8iw7p1smp_defconfig index bc86f3d..8cec706 100644 --- a/arch/arm/configs/sun8iw7p1smp_defconfig +++ b/arch/arm/configs/sun8iw7p1smp_defconfig @@ -1079,7 +1079,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y # CONFIG_DS1682 is not set # CONFIG_TI_DAC7512 is not set CONFIG_UID_STAT=y -# CONFIG_BMP085 is not set +CONFIG_BMP085=m # CONFIG_USB_SWITCH_FSA9480 is not set # CONFIG_SUNXI_BROM_READ is not set # CONFIG_C2PORT is not set @@ -1396,7 +1396,9 @@ CONFIG_INPUT_UINPUT=y # CONFIG_INPUT_GPIO is not set # CONFIG_INPUT_PCF8574 is not set # CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set -# CONFIG_INPUT_ADXL34X is not set +CONFIG_INPUT_ADXL34X=m +CONFIG_INPUT_ADXL34X_I2C=m +# CONFIG_INPUT_ADXL34X_SPI is not set # CONFIG_INPUT_CMA3000 is not set # CONFIG_INPUT_SHAFT_ENCODER is not set @@ -1461,6 +1463,10 @@ CONFIG_SERIAL_SUNXI_CONSOLE=y # CONFIG_DCC_TTY is not set # CONFIG_RAMOOPS is not set # CONFIG_SUNXI_D7S is not set +CONFIG_MATRIX_GPIO_INT=m +CONFIG_MATRIX_PWM=m +CONFIG_MATRIX_ROTARY_ENCODER=m +CONFIG_MATRIX_HCSR04=m # CONFIG_IR_CUT is not set CONFIG_SUNXI_CMATESET=y # CONFIG_SUNXI_ARISC_TEST is not set @@ -1475,7 +1481,7 @@ CONFIG_SUNXI_SOC_INFO=y CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y CONFIG_I2C_COMPAT=y -# CONFIG_I2C_CHARDEV is not set +CONFIG_I2C_CHARDEV=y # CONFIG_I2C_MUX is not set CONFIG_I2C_HELPER_AUTO=y CONFIG_I2C_ALGOBIT=y @@ -1530,7 +1536,7 @@ CONFIG_SPI_SUNXI=y # # SPI Protocol Masters # -# CONFIG_SPI_SPIDEV is not set +CONFIG_SPI_SPIDEV=y # CONFIG_SPI_TLE62X0 is not set # CONFIG_HSI is not set @@ -1602,7 +1608,29 @@ CONFIG_GPIO_SYSFS=y # MODULbus GPIO expanders: # CONFIG_GPIO_SUNXI=m -# CONFIG_W1 is not set +CONFIG_W1=y + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS1WM is not set +CONFIG_W1_MASTER_GPIO=m + +# +# 1-wire Slaves +# +CONFIG_W1_SLAVE_THERM=y +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set # CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set @@ -1677,7 +1705,7 @@ CONFIG_HWMON=y # CONFIG_SENSORS_NTC_THERMISTOR is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set -# CONFIG_SENSORS_PCF8591 is not set +CONFIG_SENSORS_PCF8591=m # CONFIG_PMBUS is not set # CONFIG_DA380 is not set # CONFIG_SENSORS_SHT15 is not set @@ -1809,7 +1837,8 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_MFD_AAT2870_CORE is not set # CONFIG_MFD_RC5T583 is not set # CONFIG_REGULATOR is not set -# CONFIG_PWM is not set +CONFIG_PWM=y +CONFIG_PWM_SUNXI=y CONFIG_MEDIA_SUPPORT=y # @@ -2574,7 +2603,7 @@ CONFIG_RTC_INTF_DEV=y # # I2C RTC drivers # -# CONFIG_RTC_DRV_DS1307 is not set +CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_DS1374 is not set # CONFIG_RTC_DRV_DS1672 is not set # CONFIG_RTC_DRV_DS3232 is not set @@ -2658,7 +2687,164 @@ CONFIG_SUNXI_DMA=y # # Microsoft Hyper-V guest support # -# CONFIG_STAGING is not set +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_ECHO is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_USB_SERIAL_QUATECH_USB2 is not set +# CONFIG_VT6656 is not set +CONFIG_IIO=y +# CONFIG_IIO_ST_HWMON is not set +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_KXSD9 is not set +# CONFIG_LIS3L02DQ is not set + +# +# Analog to digital converters +# +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD799X is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7192 is not set +# CONFIG_ADT7310 is not set +# CONFIG_ADT7410 is not set +# CONFIG_AD7280 is not set +# CONFIG_MAX1363 is not set + +# +# Analog digital bi-direction converters +# +# CONFIG_ADT7316 is not set + +# +# Capacitance to digital converters +# +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7746 is not set + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5686 is not set +# CONFIG_MAX517 is not set + +# +# Direct Digital Synthesis +# +# CONFIG_AD5930 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADXRS450 is not set + +# +# Humidity sensors +# +CONFIG_DHT11=m + +# +# Network Analyzer, Impedance Converters +# +# CONFIG_AD5933 is not set +CONFIG_INV_SENSOR=y + +# +# Light sensors +# +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_TSL2583 is not set + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843 is not set + +# +# Active energy metering IC +# +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set + +# +# Triggers - standalone +# +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_PHONE is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_SUNXIOOPS is not set CONFIG_CLKDEV_LOOKUP=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y diff --git a/arch/arm/mach-sunxi/sun8i.c b/arch/arm/mach-sunxi/sun8i.c index 2c35075..7700d04 100755 --- a/arch/arm/mach-sunxi/sun8i.c +++ b/arch/arm/mach-sunxi/sun8i.c @@ -117,6 +117,40 @@ static struct i2c_board_info i2c_ina219_devs[] __initdata = { }; #endif +/*------------------------------------------------------------------------------ + * Matrix device + */ +#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE) +#define ADXL34X_I2C_BUS (0) +static struct i2c_board_info __initdata adxl34x_i2c_bdi = { + I2C_BOARD_INFO("adxl34x", 0x1d), + .irq = -1, +}; +#endif + +#if defined(CONFIG_BMP085_MODULE) +#define BMP085_I2C_BUS (0) +static struct i2c_board_info __initdata bmp085_i2c_bdi = { + I2C_BOARD_INFO("bmp085", 0x77), + .irq = -1, +}; +#endif + +#if defined(CONFIG_RTC_DRV_DS1307_MODULE) +#define DS1307_I2C_BUS (0) +static struct i2c_board_info __initdata ds1307_i2c_bdi = { + I2C_BOARD_INFO("ds1307", 0X68), + .irq = -1, +}; +#endif + +#if defined(CONFIG_SENSORS_PCF8591_MODULE) +#define PCF8591_I2C_BUS (0) +static struct i2c_board_info __initdata pcf8591_i2c_bdi = { + I2C_BOARD_INFO("pcf8591", 0x48), +}; +#endif + #if defined(CONFIG_ION) || defined(CONFIG_ION_MODULE) #define DEFAULT_SUNXI_ION_RESERVE_SIZE 96 #define ION_CARVEOUT_INIT_MAX 4 @@ -461,6 +495,27 @@ static void __init sunxi_dev_init(void) } printk("ina219 device registered\n"); #endif + +#if defined(CONFIG_INPUT_ADXL34X_I2C_MODULE) + printk("plat: add adxl34x device\n"); + i2c_register_board_info(ADXL34X_I2C_BUS, &adxl34x_i2c_bdi, 1); +#endif + +#if defined(CONFIG_BMP085_MODULE) + printk("plat: add bmp085 device\n"); + i2c_register_board_info(BMP085_I2C_BUS, &bmp085_i2c_bdi, 1); +#endif + +#if defined(CONFIG_RTC_DRV_DS1307_MODULE) + printk("plat: add ds1307 device\n"); + i2c_register_board_info(DS1307_I2C_BUS, &ds1307_i2c_bdi, 1); +#endif + +#if defined(CONFIG_SENSORS_PCF8591_MODULE) + printk("plat: add pcf8591 device\n"); + i2c_register_board_info(PCF8591_I2C_BUS, &pcf8591_i2c_bdi, 1); +#endif + #ifdef CONFIG_ANDROID_RAM_CONSOLE /* ram console platform device initialize*/ ram_console_device_init(); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 6614788..5090528 100755 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -636,6 +636,30 @@ config SUNXI_D7S ---help--- Sunxi display 7 segment for h3. +config MATRIX_GPIO_INT + tristate "Matrix GPIO int sensor module" + default m + ---help--- + Driver for Matrix GPIO int sensor module. + +config MATRIX_PWM + tristate "Matrix PWM module" + default m + ---help--- + Driver for Matrix PWM module. + +config MATRIX_ROTARY_ENCODER + tristate "Matrix rotary encoder" + default m + ---help--- + Driver for Matrix rotary encoder. + +config MATRIX_HCSR04 + tristate "Matrix hcsr04" + default m + ---help--- + Driver for Matrix hcsr04. + source "drivers/char/sunxi_g2d/Kconfig" source "drivers/char/sunxi_ir_cut/Kconfig" source "drivers/char/cma_test/Kconfig" diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 399be2b..f0bda58 100755 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,3 +82,8 @@ obj-y += sunxi-di/ obj-${CONFIG_ID} += sunxi_id/ obj-${CONFIG_RESET_KEY} += sunxi_key/ obj-$(CONFIG_IR_CUT) += sunxi_ir_cut/ + +obj-$(CONFIG_MATRIX_GPIO_INT) += matrix_gpio_int.o +obj-$(CONFIG_MATRIX_PWM) += matrix_pwm.o +obj-$(CONFIG_MATRIX_ROTARY_ENCODER) += matrix_rotary_encoder.o +obj-$(CONFIG_MATRIX_HCSR04) += matrix_hcsr04.o \ No newline at end of file diff --git a/drivers/char/matrix_gpio_int.c b/drivers/char/matrix_gpio_int.c new file mode 100644 index 0000000..cbe29ca --- /dev/null +++ b/drivers/char/matrix_gpio_int.c @@ -0,0 +1,309 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "sensor" +#define MAX_SENDEV_NUM 8 + +struct sensor { + int gpio; + int int_type; +}; + + +struct sensor_desc { + int ID; + int gpio; + int int_type; + char *name; + int is_used; + struct timer_list timer; +}; + +static size_t sensor_num = -1; // number of sensor has been registered +static int is_started = 0; +static struct semaphore lock; + +static struct sensor_desc sensor_dev[MAX_SENDEV_NUM] = { + { 0, -1, -1, "gpio_int_sensor1"}, + { 1, -1, -1, "gpio_int_sensor2"}, + { 2, -1, -1, "gpio_int_sensor3"}, + { 3, -1, -1, "gpio_int_sensor4"}, + { 4, -1, -1, "gpio_int_sensor5"}, + { 5, -1, -1, "gpio_int_sensor6"}, + { 6, -1, -1, "gpio_int_sensor7"}, + { 7, -1, -1, "gpio_int_sensor8"}, +}; + +static volatile char sensor_dev_value[MAX_SENDEV_NUM] = { +}; + +static DECLARE_WAIT_QUEUE_HEAD(sensor_dev_waitq); + +static volatile int ev_press = 0; + +// static int timer_counter = 0; +static void gpio_int_sensors_timer(unsigned long _data) +{ + + struct sensor_desc *bdata = (struct sensor_desc *)_data; + int ID; + unsigned tmp = gpio_get_value(bdata->gpio); + ID = bdata->ID; + + // printk("%s %d value=%d int_type=%d\n", __FUNCTION__, timer_counter++, tmp, bdata->int_type); + if (bdata->int_type == IRQ_TYPE_EDGE_RISING) { + if(tmp == 1) { + sensor_dev_value[ID] = 1; + ev_press = 1; + wake_up_interruptible(&sensor_dev_waitq); + } + } else if (bdata->int_type == IRQ_TYPE_EDGE_FALLING) { + if(tmp == 0) { + sensor_dev_value[ID] = 1; + ev_press = 1; + wake_up_interruptible(&sensor_dev_waitq); + } + } else if (bdata->int_type == IRQ_TYPE_EDGE_BOTH) { + sensor_dev_value[ID] = tmp; + ev_press = 1; + wake_up_interruptible(&sensor_dev_waitq); + } +} + +// static int int_counter=0; +static irqreturn_t gpio_int_sensor_interrupt(int irq, void *dev_id) +{ + // printk("%s %d\n", __FUNCTION__, int_counter++); + struct sensor_desc *bdata = (struct sensor_desc *)dev_id; + mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(100)); + return IRQ_HANDLED; +} + +static int start_all_sensor(void) +{ + int irq; + int i; + int err = 0; + + for (i = 0; i < sensor_num; i++) { + if (!sensor_dev[i].gpio) + continue; + + setup_timer(&sensor_dev[i].timer, gpio_int_sensors_timer, + (unsigned long)&sensor_dev[i]); + + err = gpio_request(sensor_dev[i].gpio, "gpio_int_sensor"); + if (err) { + printk("%s gpio_request %d fail\n", __FUNCTION__, sensor_dev[i].gpio); + break; + } + + irq = gpio_to_irq(sensor_dev[i].gpio); + err = request_irq(irq, gpio_int_sensor_interrupt, IRQ_TYPE_EDGE_FALLING, + sensor_dev[i].name, (void *)&sensor_dev[i]); + if (err) { + printk("%s request_irq %d fail\n", __FUNCTION__, irq); + break; + } + } + + if (err) { + i--; + for (; i >= 0; i--) { + if (!sensor_dev[i].gpio) + continue; + + gpio_free(sensor_dev[i].gpio); + irq = gpio_to_irq(sensor_dev[i].gpio); + disable_irq(irq); + free_irq(irq, (void *)&sensor_dev[i]); + + del_timer_sync(&sensor_dev[i].timer); + } + + return -EBUSY; + } + + ev_press = 0; + return 0; +} + +static int gpio_int_sensors_open(struct inode *inode, struct file *file) +{ + if (down_trylock(&lock)) + return -EBUSY; + sensor_num = 0; + is_started = 0; + return 0; +} + +static int stop_all_sensor(void) +{ + int irq, i; + + for (i = 0; i < sensor_num; i++) { + if (!sensor_dev[i].gpio) + continue; + + gpio_free(sensor_dev[i].gpio); + irq = gpio_to_irq(sensor_dev[i].gpio); + free_irq(irq, (void *)&sensor_dev[i]); + + del_timer_sync(&sensor_dev[i].timer); + } + return 0; +} + +static int gpio_int_sensors_close(struct inode *inode, struct file *file) +{ + // printk("%s sensor_num=%d is_started=%d\n",__FUNCTION__, sensor_num, is_started); + if (is_started && sensor_num > 0) { + stop_all_sensor(); + } + sensor_num = -1; + is_started = 0; + ev_press = 0; + up(&lock); + return 0; +} + +// static int read_counter = 0; +static int gpio_int_sensors_read(struct file *filp, char __user *buff, + size_t count, loff_t *offp) +{ + unsigned long err; + int i = 0; + + if (!ev_press) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + else + wait_event_interruptible(sensor_dev_waitq, ev_press); + } + + ev_press = 0; + + err = copy_to_user((void *)buff, (const void *)(&sensor_dev_value), + min(sensor_num, count)); + for (i = 0; i= MAX_SENDEV_NUM) + return -EBUSY; + argp = (void __user *)arg; + if (copy_from_user(&sen, argp, sizeof sen)) + return -EINVAL; + sensor_dev[sensor_num].gpio = sen.gpio; + sensor_dev[sensor_num].int_type= sen.int_type; + sensor_num++; + break; + case DEL_SENSOR: + del_dev = (int)arg; + // printk("%s del_dev=%d\n", __func__, del_dev); + if (is_started != 0 || sensor_num <= 0 || del_dev != sensor_num) + return -EINVAL; + sensor_dev[sensor_num].gpio = -1; + sensor_dev[sensor_num].int_type= -1; + sensor_num--; + break; + case START_ALL_SENSOR: + if (is_started != 0 || sensor_num <= 0) + return -EBUSY; + if((ret = start_all_sensor()) < 0) + return ret; + is_started = 1; + break; + case STOP_ALL_SENSOR: + if (is_started != 1 || sensor_num <= 0) + return -EBUSY; + stop_all_sensor(); + is_started = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + + +static struct file_operations dev_fops = { + .owner = THIS_MODULE, + .open = gpio_int_sensors_open, + .release = gpio_int_sensors_close, + .read = gpio_int_sensors_read, + .poll = gpio_int_sensors_poll, + .unlocked_ioctl = gpio_int_sensors_ioctl, +}; + +static struct miscdevice misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &dev_fops, +}; + +static int __init sensor_dev_init(void) +{ + printk("Matirx GPIO Int sensor init\n"); + sema_init(&lock, 1); + return misc_register(&misc); +} + +static void __exit sensor_dev_exit(void) +{ + printk("Matirx GPIO Int sensor exit\n"); + misc_deregister(&misc); +} + +module_init(sensor_dev_init); +module_exit(sensor_dev_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FriendlyARM Inc."); + diff --git a/drivers/char/matrix_hcsr04.c b/drivers/char/matrix_hcsr04.c new file mode 100644 index 0000000..3f4961b --- /dev/null +++ b/drivers/char/matrix_hcsr04.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("DA BAI"); +MODULE_DESCRIPTION("Driver for HC-SR04 ultrasonic sensor"); + +// #define HCSR04_IRQ_DEUBG +struct HCSR04_resource { + int pin; +}; + +static int HCSR04_PIN = -1; +static int hasResource = 0; +static int irq_num = 0; +static int irq_time[3]; +static int valid_value = 0; +static DECLARE_WAIT_QUEUE_HEAD(hcsr_waitq); + +static int hcsr04_hwexit(void); +static int hcsr04_hwinit(void); +static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf); +static irqreturn_t gpio_isr(int irq, void *data); + +static ssize_t hcsr04_value_write(struct class *class, struct class_attribute *attr, const char *buf, size_t len) +{ + struct HCSR04_resource *res; + if (len == 4) { + res = (struct HCSR04_resource *)buf; + + if (res->pin != -1 && hasResource == 0) { + HCSR04_PIN = res->pin; + if (hcsr04_hwinit() == -1) { + return -1; + } + hasResource = 1; + } else if (res->pin == -1 && hasResource == 1) { + if (hcsr04_hwexit() == -1) { + return -1; + } + hasResource = 0; + } + } + return len; +} + +// This function is called when you read /sys/class/hcsr04/value +static ssize_t hcsr04_value_read(struct class *class, struct class_attribute *attr, char *buf) +{ + int ret = -1; + int gpio_irq=-1; + + if (hasResource == 0) { + return 0; + } + irq_num = 0; + valid_value = 0; + gpio_direction_output(HCSR04_PIN, 0); + udelay(50); + gpio_set_value(HCSR04_PIN, 1); + udelay(50); + gpio_set_value(HCSR04_PIN, 0); + udelay(50); + + ret = gpio_to_irq(HCSR04_PIN); + if (ret < 0) { + printk(KERN_ERR"%s fail to gpio_to_irq\n", __func__); + goto fail; + } else { + gpio_irq = ret; + } + + ret = request_irq(gpio_irq, gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING , "hc-sr04", NULL); + if (ret) { + printk(KERN_ERR"%s fail to request_irq\n", __func__); + goto fail; + } + + if(wait_event_interruptible_timeout(hcsr_waitq, valid_value, HZ) == 0) { + printk(KERN_ERR"%s timeout\n", __func__); + free_irq(gpio_irq, NULL); + goto fail; + } + free_irq(gpio_irq, NULL); +#ifdef HCSR04_IRQ_DEUBG + printk("%s irq_time[1]=%d irq_time[0]=%d %d\n", __func__, irq_time[1], irq_time[0], irq_time[1]-irq_time[0]); +#endif + return sprintf(buf, "%d\n", irq_time[1]-irq_time[0]); + fail: + return sprintf(buf, "%d\n", -1);; +} + +// Sysfs definitions for hcsr04 class +static struct class_attribute hcsr04_class_attrs[] = { + __ATTR(value, S_IRUGO | S_IWUSR, hcsr04_value_read, hcsr04_value_write), + __ATTR_NULL, +}; + +// Name of directory created in /sys/class +static struct class hcsr04_class = { + .name = "hcsr04", + .owner = THIS_MODULE, + .class_attrs = hcsr04_class_attrs, +}; + +// Interrupt handler on ECHO signal +static irqreturn_t gpio_isr(int irq, void *data) +{ + if (valid_value == 0) { + if((irq_num == 0 && gpio_get_value(HCSR04_PIN) != 1) || + (irq_num == 1 && gpio_get_value(HCSR04_PIN) != 0) || + (irq_num == 2 && gpio_get_value(HCSR04_PIN) != 1) + ) { + return IRQ_HANDLED; + } + irq_time[irq_num] = ktime_to_us(ktime_get()); + if(irq_num == 2) { +#ifdef HCSR04_IRQ_DEUBG + int i = 0; + for(i=0; i<3; i++) + printk("%d:%d\n", i, irq_time[i]); +#endif + valid_value = 1; + wake_up_interruptible(&hcsr_waitq); + return IRQ_HANDLED; + } + irq_num++; + } + return IRQ_HANDLED; +} + +static int hcsr04_hwinit(void) +{ + int rtc; + + rtc=gpio_request(HCSR04_PIN, "HCSR04"); + if (rtc!=0) { + printk(KERN_INFO "Error %d\n",__LINE__); + goto fail; + } + return 0; + + fail: + return -1; +} + +static int hcsr04_init(void) +{ + printk(KERN_INFO "HC-SR04 driver v0.32 initializing.\n"); + + if (class_register(&hcsr04_class)<0) + goto fail; + return 0; + + fail: + return -1; + +} + +static int hcsr04_hwexit(void) +{ + gpio_free(HCSR04_PIN); + return 0; +} + +static void hcsr04_exit(void) +{ + class_unregister(&hcsr04_class); + printk(KERN_INFO "HC-SR04 disabled.\n"); +} + +module_init(hcsr04_init); +module_exit(hcsr04_exit); + diff --git a/drivers/char/matrix_pwm.c b/drivers/char/matrix_pwm.c new file mode 100644 index 0000000..5cdd951 --- /dev/null +++ b/drivers/char/matrix_pwm.c @@ -0,0 +1,206 @@ +/* + * linux/drivers/char/matrix_pwm.c + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DEVICE_NAME "pwm" +#define PWM_NUM (2) +#define PWM_IOCTL_SET_FREQ (0x1) +#define PWM_IOCTL_STOP (0x0) +#define NS_IN_1HZ (1000000000UL) + +static int is_pwm_working[PWM_NUM] = {0, 0}; +static struct pwm_device *matrix_pwm[PWM_NUM]; +static struct semaphore lock; + +static int pwm_set_freq(int index, int pin, unsigned long freq, int duty) +{ + int ret=0; + int period_ns = NS_IN_1HZ / freq; + int duty_ns = period_ns / 1000 * duty; + + printk("%s %d %d\n", __func__, period_ns, duty_ns); + if ((ret = pwm_config(matrix_pwm[index], duty_ns, period_ns))) { + printk("fail to pwm_config\n"); + return ret; + } + if ((ret = pwm_enable(matrix_pwm[index]))) { + printk("fail to pwm_enable\n"); + return ret; + } + return ret; +} + +static void pwm_stop(int index, int pin) +{ + pwm_config(matrix_pwm[index], 0, NS_IN_1HZ / 100); + pwm_disable(matrix_pwm[index]); +} + +static int matrix_pwm_hw_init(int index, int pin) +{ + int ret=0; + +#if 0 + ret = gpio_request(pin, DEVICE_NAME); + if (ret) { + printk("request gpio %d for pwm failed\n", pin); + return ret; + } + gpio_direction_output(pin, 0); +#endif + + matrix_pwm[index] = pwm_request(index, DEVICE_NAME); + if (IS_ERR(matrix_pwm[index])) { + printk("request pwm%d failed\n", index); +#if 0 + gpio_free(pin); +#endif + return -ENODEV; + } + + pwm_stop(index, pin); + return ret; +} + +static void matrix_pwm_hw_exit(int index,int pin) +{ + pwm_stop(index, pin); + pwm_free(matrix_pwm[index]); +#if 0 + gpio_free(pin); +#endif +} + +static int matrix_pwm_open(struct inode *inode, struct file *file) { + if (!down_trylock(&lock)) + return 0; + else + return -EBUSY; +} + +static int matrix_pwm_close(struct inode *inode, struct file *file) { + up(&lock); + return 0; +} + +static long matrix_pwm_ioctl(struct file *filep, unsigned int cmd,unsigned long arg) +{ + int pwm_id; + int param[3]; + int gpio; + int freq; + int duty; + int ret; + + switch (cmd) { + case PWM_IOCTL_SET_FREQ: + if (copy_from_user(param, (void __user *)arg, sizeof(param))) + return -EINVAL; + gpio = param[0]; + freq = param[1]; + duty = param[2]; + if (gpio == (SUNXI_PA_BASE + 5)) { + pwm_id = 0; + } else if (gpio == (SUNXI_PA_BASE + 6)) { + pwm_id = 1; + } else { + printk("Invalid pwm gpio %d\n", gpio); + return -EINVAL; + } + + if (duty < 0 || duty > 1000) { + printk("Invalid pwm duty %d\n", duty); + return -EINVAL; + } + + if (is_pwm_working[pwm_id] == 1) { + matrix_pwm_hw_exit(pwm_id, gpio); + } + + if ((ret = matrix_pwm_hw_init(pwm_id, gpio))) { + return ret; + } + is_pwm_working[pwm_id] = 1; + if ((ret = pwm_set_freq(pwm_id, gpio, freq, duty))) { + return ret; + } + break; + case PWM_IOCTL_STOP: + if (copy_from_user(&gpio, (void __user *)arg, sizeof(gpio))) + return -EINVAL; + if (gpio == (SUNXI_PA_BASE + 5)) { + pwm_id = 0; + } else if (gpio == (SUNXI_PA_BASE + 6)) { + pwm_id = 1; + } else { + printk("Invalid pwm gpio %d\n", gpio); + return -EINVAL; + } + if (is_pwm_working[pwm_id] == 1) { + matrix_pwm_hw_exit(pwm_id, gpio); + is_pwm_working[pwm_id] = 0; + } + break; + default: + printk("%s unsupported pwm ioctl %d", __FUNCTION__, cmd); + break; + } + + return 0; +} + +static struct file_operations matrix_pwm_ops = { + .owner = THIS_MODULE, + .open = matrix_pwm_open, + .release = matrix_pwm_close, + .unlocked_ioctl = matrix_pwm_ioctl, +}; + +static struct miscdevice matrix_misc_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &matrix_pwm_ops, +}; + +static int __init matrix_pwm_init(void) +{ + int ret; + ret = misc_register(&matrix_misc_dev); + printk("Matirx PWM init\n"); + + sema_init(&lock, 1); + return ret; +} + +static void __exit matrix_pwm_exit(void) { + misc_deregister(&matrix_misc_dev); + printk("Matirx PWM exit\n"); +} + +module_init(matrix_pwm_init); +module_exit(matrix_pwm_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("FriendlyARM Inc."); +MODULE_DESCRIPTION("FriendlyARM Matrix PWM Driver"); + diff --git a/drivers/char/matrix_rotary_encoder.c b/drivers/char/matrix_rotary_encoder.c new file mode 100644 index 0000000..97fcb76 --- /dev/null +++ b/drivers/char/matrix_rotary_encoder.c @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int has_init = 0; +static int sw_pin = -1; // func: int +static int sia_pin = -1; // func: int +static int sib_pin = -1; // func: input +static int sia_irq = -1; +static int sw_irq = -1; +static int counter = 0; +static int sw = 0; + +static void rotary_sensor_hw_exit(void); +static int rotary_sensor_hw_init(void ); + + +static ssize_t rotary_sensor_sw_read(struct device *dev, struct device_attribute *attr, char *buf) +{ + if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) { + return sprintf(buf, "%d\n", sw); + } + return -1; +} + +static ssize_t rotary_sensor_value_read(struct device *dev, struct device_attribute *attr, char *buf) +{ + if ( sw_pin != -1 && sia_pin != -1 && sib_pin != -1) { + return sprintf(buf, "%d\n", counter); + } + return -1; +} + +static ssize_t rotary_sensor_gpio_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d,%d,%d\n", sw_pin, sia_pin, sib_pin); +} + +static ssize_t rotary_sensor_gpio_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) +{ + if ( has_init ==0 ) { + sscanf(buf,"%d,%d,%d ", &sw_pin, &sia_pin, &sib_pin); + printk(KERN_ERR"buf=%s\n", buf); + if (rotary_sensor_hw_init()) { + has_init = 0; + return -1; + } + else { + has_init = 1; + } + } else { + rotary_sensor_hw_exit(); + has_init = 0; + } + + return count; +} +static struct device_attribute value_attr = __ATTR(value, S_IRUGO, rotary_sensor_value_read, NULL); +static struct device_attribute sw_attr = __ATTR(sw,S_IRUGO, rotary_sensor_sw_read, NULL); +static struct device_attribute gpio_attr = __ATTR(gpio, S_IRUGO|S_IWUGO, rotary_sensor_gpio_show, rotary_sensor_gpio_store); + +/* sys attribte group */ +static struct attribute *attrs[] = { + &value_attr.attr, &sw_attr.attr, &gpio_attr.attr, NULL, +}; + +static struct attribute_group attr_group = { + .attrs = (struct attribute **)attrs, +}; + + +static irqreturn_t sw_isr(int irq, void *data) +{ + if (gpio_get_value(sw_pin) == 1) { + sw = 0; + } else { + sw = 1; + } + // printk("%s sw=%d\n", __func__, sw); + return IRQ_HANDLED; +} + +static irqreturn_t rotate_isr(int irq, void *data) +{ + if (gpio_get_value(sib_pin) == 1) { + counter++; + } else { + counter--; + } + // printk("%s value=%d\n", __func__, counter); + return IRQ_HANDLED; +} + +static void rotary_sensor_hw_exit(void) +{ + if (sia_irq != -1) + free_irq(sia_irq, NULL); + if (sw_irq != -1) + free_irq(sw_irq, NULL); + if (sib_pin != -1) + gpio_free(sib_pin); + if (sia_pin != -1) + gpio_free(sia_pin); + if (sw_pin != -1) + gpio_free(sw_pin); + sw_pin = sia_pin = sib_pin = -1; +} + +static int rotary_sensor_hw_init(void ) +{ + int ret = -1; + + ret = gpio_request(sw_pin, "sw"); + if (ret) { + printk(KERN_ERR"gpio request sw_pin fail:%d\n", sw_pin); + return -1; + } + ret = gpio_request(sia_pin, "sia_pin"); + if (ret) { + printk(KERN_ERR"gpio request sia_pin fail:%d\n", sia_pin); + goto fail_gpio_sw; + } + ret = gpio_request(sib_pin, "sib_pin"); + if (ret) { + printk(KERN_ERR"gpio request sib_pin fail:%d\n", sia_pin); + goto fail_gpio_sia; + } + + sw_irq = gpio_to_irq(sw_pin); + ret = request_irq(sw_irq, sw_isr, IRQ_TYPE_EDGE_BOTH, "rotary_sensor_sw", NULL); + if (ret) { + printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sw_pin, sw_irq); + goto fail_gpio_sib; + } + + sia_irq = gpio_to_irq(sia_pin); + ret = request_irq(sia_irq, rotate_isr, IRQ_TYPE_EDGE_FALLING , "rotary_sensor_sia", NULL); + if (ret) { + printk(KERN_ERR"%s fail to request_irq, gpio=%d irq=%d\n", __func__, sia_pin, sia_irq); + goto fail_irq_sw; + } + + gpio_direction_input(sib_pin); + + return ret; + +fail_irq_sw: + free_irq(sw_irq, NULL); +fail_gpio_sib: + gpio_free(sib_pin); +fail_gpio_sia: + gpio_free(sia_pin); +fail_gpio_sw: + gpio_free(sw_pin); + return ret; + +} +static struct kobject *kobj = NULL; +static int rotary_sensor_init(void) +{ + int ret = 0; + printk(KERN_INFO "Matrix-rotary_encoder init.\n"); + + kobj = kobject_create_and_add("rotary_encoder", &platform_bus.kobj); + if (!kobj) { + pr_err("%s: failed to kobject_create_and_add for rotary_encoder\n", __func__); + return -EINVAL; + } + + ret = sysfs_create_group(kobj, &attr_group); + if (ret) { + pr_err("%s: failed to sysfs_create_group for rotary_encoder\n", __func__); + kobject_del(kobj); + return -EINVAL; + } + return ret; +} + +static void rotary_sensor_exit(void) +{ + printk(KERN_INFO "Matrix-rotary_encoder exit.\n"); + sysfs_remove_group(kobj, &attr_group); + kobject_put(kobj); + kobj = NULL; +} + +module_init(rotary_sensor_init); +module_exit(rotary_sensor_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("FriendlyARM"); +MODULE_DESCRIPTION("Driver for Matrix-Rotary_Sensor"); diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 1cf72fe..81fbe55 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -223,7 +223,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = { .free_fall_threshold = 8, .free_fall_time = 0x20, .data_rate = 8, - .data_range = ADXL_FULL_RES, + .data_range = ADXL_FULL_RES | INT_INVERT, .ev_type = EV_ABS, .ev_code_x = ABS_X, /* EV_REL */ @@ -236,6 +236,9 @@ static const struct adxl34x_platform_data adxl34x_default_init = { .watermark = 0, }; +static irqreturn_t adxl34x_irq(int irq, void *handle); +static int adxl34x_read_without_int(int irq, void* handle); + static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis) { short buf[3]; @@ -296,6 +299,14 @@ static void adxl34x_do_tap(struct adxl34x *ac, adxl34x_send_key_events(ac, pdata, status, false); } +static int adxl34x_read_without_int(int irq, void* handle) +{ + if (adxl34x_irq(irq, handle) != IRQ_HANDLED) { + return -1; + } + return 0; +} + static irqreturn_t adxl34x_irq(int irq, void *handle) { struct adxl34x *ac = handle; @@ -486,6 +497,10 @@ static ssize_t adxl34x_calibrate_show(struct device *dev, struct adxl34x *ac = dev_get_drvdata(dev); ssize_t count; + if (adxl34x_read_without_int(0, ac)) { + return 0; + } + mutex_lock(&ac->mutex); count = sprintf(buf, "%d,%d,%d\n", ac->hwcal.x * 4 + ac->swcal.x, @@ -607,6 +622,9 @@ static ssize_t adxl34x_position_show(struct device *dev, struct adxl34x *ac = dev_get_drvdata(dev); ssize_t count; + if (adxl34x_read_without_int(0, ac)) { + return 0; + } mutex_lock(&ac->mutex); count = sprintf(buf, "(%d, %d, %d)\n", ac->saved.x, ac->saved.y, ac->saved.z); @@ -810,14 +828,16 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, ac->fifo_delay = false; ac->bops->write(dev, POWER_CTL, 0); - + // not use int +#if 0 err = request_threaded_irq(ac->irq, NULL, adxl34x_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, dev_name(dev), ac); if (err) { dev_err(dev, "irq %d busy?\n", ac->irq); goto err_free_mem; } +#endif err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group); if (err) @@ -884,6 +904,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK); + __adxl34x_enable(ac); +#if 0 + int start = 0x1D; + for(; start < 0x3C; start++) { + printk("reg[%x]=%x\n", start, AC_READ(ac, start)); + } +#endif return ac; err_remove_attr: diff --git a/drivers/staging/iio/humidity/Makefile b/drivers/staging/iio/humidity/Makefile new file mode 100644 index 0000000..d5d36c0 --- /dev/null +++ b/drivers/staging/iio/humidity/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for IIO humidity sensor drivers +# + +obj-$(CONFIG_DHT11) += dht11.o diff --git a/drivers/staging/iio/humidity/dht11.c b/drivers/staging/iio/humidity/dht11.c new file mode 100644 index 0000000..a751a54 --- /dev/null +++ b/drivers/staging/iio/humidity/dht11.c @@ -0,0 +1,366 @@ +/* + * DHT11/DHT22 bit banging GPIO driver + * + * Copyright (c) Harald Geyer + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../iio.h" + +//#define DHT11_DEBUG 1 +#define DRIVER_NAME "dht11" + +#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */ + +#define DHT11_EDGES_PREAMBLE 4 +#define DHT11_BITS_PER_READ 40 +#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE) + +/* Data transmission timing (nano seconds) */ +#define DHT11_START_TRANSMISSION 18 /* ms */ +#define DHT11_SENSOR_RESPONSE 80000 +#define DHT11_START_BIT 50000 +#define DHT11_DATA_BIT_LOW 27000 +#define DHT11_DATA_BIT_HIGH 70000 + +#define DATA_START_FLAG_MIN (50000) +#define DATA_START_FLAG_MAX (60000) +#define DATA_ONE_MIN (65000) +#define DATA_ONE_MAX (75000) +#define DATA_ZERO_MIN (20000) +#define DATA_ZERO_MAX (30000) + + +struct dht11 { + struct device *dev; + + int gpio; + int irq; + + struct completion completion; + + s64 timestamp; + int temperature; + int humidity; + + /* num_edges: -1 means "no transmission in progress" */ + int num_edges; + struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ]; +}; + +static int gpio = -1; +static int dht11_read_flag = 0; +static unsigned char dht11_decode_byte(int *timing) +{ + unsigned char ret = 0; + int i; + + for (i = 0; i < 8; ++i) { + ret <<= 1; + ret +=timing[i]; + } + + return ret; +} + +static int dht11_decode(struct dht11 *dht11, int *timing) +{ + unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; + +#ifdef DHT11_DEBUG + int i = 0; + for(i=0; idev, + "checksum error %d %d %d %d %d\n", + hum_int, hum_dec, temp_int, temp_dec, checksum); + return -EIO; + } + + dht11->timestamp = iio_get_time_ns(); + if (hum_int < 20) { /* DHT22 */ + dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * + ((temp_int & 0x80) ? -100 : 100); + dht11->humidity = ((hum_int << 8) + hum_dec) * 100; + } else if (temp_dec == 0 && hum_dec == 0) { /* DHT11 */ + dht11->temperature = temp_int * 1000; + dht11->humidity = hum_int * 1000; + } else { + dev_err(dht11->dev, + "Don't know how to decode data: %d %d %d %d\n", + hum_int, hum_dec, temp_int, temp_dec); + return -EIO; + } + + return 0; +} + +static int dht11_read_thread(void *__dev) +{ + struct dht11 *dht11 = (struct dht11 *)__dev; + int value = 0; + +#ifdef DHT11_DEBUG + printk(KERN_INFO"%s start\n", __func__); +#endif + if (gpio_direction_output(dht11->gpio, 0)) + return -1; + msleep(DHT11_START_TRANSMISSION); + gpio_direction_input(dht11->gpio); + dht11->edges[dht11->num_edges].value = gpio_get_value(dht11->gpio); + dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + while (dht11->num_edges < DHT11_EDGES_PER_READ && dht11_read_flag == 1) { + value = gpio_get_value(dht11->gpio); + if (dht11->edges[dht11->num_edges].value != value) { + dht11->num_edges++; + dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges].value = value; + if (dht11->num_edges == DHT11_EDGES_PER_READ) + complete(&dht11->completion); + } + } + return 0; +} + +static int dht11_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long m) +{ + struct dht11 *dht11 = iio_priv(iio_dev); + int ret; + int i, j; + int timing[DHT11_BITS_PER_READ], time; + struct task_struct *th; + + if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + dht11->num_edges = 0; + dht11->completion.done = 0; + th = kthread_create(dht11_read_thread, dht11, "dht11-read"); + if (IS_ERR(th)) { + ret = -1; + goto err; + } + dht11_read_flag = 1; + wake_up_process(th); + ret = wait_for_completion_killable_timeout(&dht11->completion, HZ); + dht11_read_flag = 0; + if(th) + kthread_stop(th); + if (ret == 0) { + dev_err(&iio_dev->dev, "dht11 read raw timeout\n"); + ret = -1; + //goto err; + } + for(i=0,j=0; inum_edges; i++) { + if (i != 0) { +#ifdef DHT11_DEBUG + printk(KERN_DEBUG"%02d ts=%lld value=%d pass=%lld\n", i, dht11->edges[i].ts, dht11->edges[i].value, dht11->edges[i].ts - dht11->edges[i-1].ts); +#endif + time = dht11->edges[i].ts - dht11->edges[i-1].ts; + } + if (i > 3) { + if ((i%2) == 0) { // one bit start always about 50us + if (timeDATA_START_FLAG_MAX) { + printk(KERN_ERR"bit start without 50us, time=%d\n", time); + ret = -EINVAL; + goto err; + } + } else { + time = dht11->edges[i].ts - dht11->edges[i-1].ts; + if (time > DATA_ZERO_MIN && time < DATA_ZERO_MAX) + timing[j] = 0; + else if (time > DATA_ONE_MIN && time < DATA_ONE_MAX) + timing[j]= 1; + else { + printk(KERN_ERR"bit value is not 1 or 0, time=%d\n", time); + ret = -EINVAL; + goto err; + } + j++; + } + } + } + + ret = dht11_decode(dht11, timing); + if (ret) + goto err; + } + + ret = IIO_VAL_INT; + if (chan->type == IIO_TEMP) + *val = dht11->temperature; + else if (chan->type == IIO_HUMIDITYRELATIVE) + *val = dht11->humidity; + else + ret = -EINVAL; +err: + dht11->num_edges = -1; + return ret; +} + +static const struct iio_info dht11_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = dht11_read_raw, +}; + +static const struct iio_chan_spec dht11_chan_spec[] = { + { + .type = IIO_TEMP, + .processed_val = IIO_PROCESSED, + }, + { + .type = IIO_HUMIDITYRELATIVE, + .processed_val = IIO_PROCESSED, + } +}; + +static const struct of_device_id dht11_dt_ids[] = { + { .compatible = "dht11", }, + { } +}; +MODULE_DEVICE_TABLE(of, dht11_dt_ids); + +static int dht11_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dht11 *dht11; + struct iio_dev *iio; + int ret = -1; + + iio = iio_allocate_device(sizeof(*dht11)); + if (!iio) { + dev_err(dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + dht11 = iio_priv(iio); + dht11->dev = dev; + dht11->gpio = gpio; + + ret = gpio_request(dht11->gpio, pdev->name); + if (ret) + return ret; + + dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->num_edges = -1; + + platform_set_drvdata(pdev, iio); + + init_completion(&dht11->completion); + iio->name = pdev->name; + iio->dev.parent = &pdev->dev; + iio->info = &dht11_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = dht11_chan_spec; + iio->num_channels = ARRAY_SIZE(dht11_chan_spec); + + return iio_device_register(iio); +} + +static int dht11_remove(struct platform_device *pdev) +{ + struct iio_dev *iio = platform_get_drvdata(pdev); + struct dht11 *dht11 = iio_priv(iio); + + iio_device_unregister(iio); + gpio_free(dht11->gpio); + iio_free_device(iio); + return 0; +} + +static struct platform_driver dht11_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = dht11_dt_ids, + }, + .probe = dht11_probe, + .remove = dht11_remove, +}; + +void matrix_dht11_device_release(struct device *dev) +{ +} + +static struct platform_device dht11_device = { + .name = "dht11", + .id = -1, + .num_resources = 0, + .dev = { + .release = matrix_dht11_device_release, + } +}; + +static int __init dht11_init(void) +{ + int ret = -1; + + printk("plat: add device matrix-dht11, gpio=%d\n", gpio); + if ((ret = platform_device_register(&dht11_device))) { + return ret; + } + + if ((ret = platform_driver_register(&dht11_driver))) { + platform_device_unregister(&dht11_device); + } + return ret; +} + +static void __exit dht11_exit(void) +{ + platform_driver_unregister(&dht11_driver); + platform_device_unregister(&dht11_device); + gpio = -1; +} + +module_init(dht11_init); +module_exit(dht11_exit); +MODULE_AUTHOR("Harald Geyer "); +MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver"); +MODULE_LICENSE("GPL v2"); +module_param(gpio, int, 0644); diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index e16500a..7e4421e 100755 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -68,6 +68,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_ANGL] = "angl", [IIO_TIMESTAMP] = "timestamp", [IIO_CAPACITANCE] = "capacitance", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", [IIO_QUATERNION] = "quaternion", }; diff --git a/drivers/staging/iio/types.h b/drivers/staging/iio/types.h index 291c783..616c141 100755 --- a/drivers/staging/iio/types.h +++ b/drivers/staging/iio/types.h @@ -27,6 +27,7 @@ enum iio_chan_type { IIO_ANGL, IIO_TIMESTAMP, IIO_CAPACITANCE, + IIO_HUMIDITYRELATIVE, IIO_QUATERNION, }; diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index c5a3e96..88ee685 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -8,5 +8,5 @@ obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o -obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o +obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o w1-gpio-board.o obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o diff --git a/drivers/w1/masters/w1-gpio-board.c b/drivers/w1/masters/w1-gpio-board.c new file mode 100644 index 0000000..11aa1e4 --- /dev/null +++ b/drivers/w1/masters/w1-gpio-board.c @@ -0,0 +1,59 @@ +/* + * w1-gpio-board.c - Board driver for GPIO w1 bus master + * + * Copyright (C) 2016 FriendlyARM (www.friendlyarm.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. + */ +#include +#include +#include +#include +#include +#include + +#include + +static int gpio = -1; +module_param(gpio, int, 0644); + + +static struct w1_gpio_platform_data w1_gpio_pdata = { + .pin = -1, + .is_open_drain = 0, +}; + +static void w1_device_release(struct device *dev) { + // nothing here yet +} + +static struct platform_device matrix_w1_device = { + .name = "w1-gpio", + .id = -1, + .dev = { + .release = w1_device_release, + .platform_data = &w1_gpio_pdata, + } +}; + + +static int __init w1_gpio_board_init(void) +{ + w1_gpio_pdata.pin = gpio; + printk("plat: add device w1-gpio, gpio=%d\n", w1_gpio_pdata.pin); + return platform_device_register(&matrix_w1_device); +} + +static void __exit w1_gpio_board_exit(void) +{ + platform_device_unregister(&matrix_w1_device); +} + +module_init(w1_gpio_board_init); +module_exit(w1_gpio_board_exit); + +MODULE_DESCRIPTION("Board driver for GPIO w1 bus master"); +MODULE_AUTHOR("FriendlyARM"); +MODULE_LICENSE("GPL"); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index df600d1..28f8d7d 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -42,7 +42,7 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } -static int __init w1_gpio_probe(struct platform_device *pdev) +static int w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -56,8 +56,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev) return -ENOMEM; err = gpio_request(pdata->pin, "w1"); - if (err) + if (err) { + dev_err(&pdev->dev, "failed to request GPIO %d\n", pdata->pin); goto free_master; + } master->data = pdata; master->read_bit = w1_gpio_read_bit; @@ -89,7 +91,7 @@ static int __init w1_gpio_probe(struct platform_device *pdev) return err; } -static int __exit w1_gpio_remove(struct platform_device *pdev) +static int w1_gpio_remove(struct platform_device *pdev) { struct w1_bus_master *master = platform_get_drvdata(pdev); struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -136,14 +138,15 @@ static struct platform_driver w1_gpio_driver = { .name = "w1-gpio", .owner = THIS_MODULE, }, - .remove = __exit_p(w1_gpio_remove), + .probe = w1_gpio_probe, + .remove = w1_gpio_remove, .suspend = w1_gpio_suspend, .resume = w1_gpio_resume, }; static int __init w1_gpio_init(void) { - return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); + return platform_driver_register(&w1_gpio_driver); } static void __exit w1_gpio_exit(void)