/** * Driver write function * * This function uses a generic SPI write to send values to the Pmod device * It takes a raw data array from the app in the buffer, copied it into * device dispay buffer, and finally sends the buffer to the OLED using SPI */ static ssize_t gpio_pmodoled_write(struct file *fp, const char __user *buffer, size_t length, loff_t *offset) { ssize_t retval = 0; struct gpio_pmodoled_device *dev; unsigned int minor_id; int cnt; int status; dev = fp->private_data; minor_id = MINOR(dev->dev_id); if(mutex_lock_interruptible(&dev->mutex)) { retval = -ERESTARTSYS; goto write_lock_err; } if (buffer == NULL) { dev_err(&dev->spi->dev, "oled_write: ERROR: invalid buffer address: 0x%08x\n", (unsigned int) buffer); retval = -EINVAL; goto quit_write; } if(length > DISPLAY_BUF_SZ) { cnt = DISPLAY_BUF_SZ; } else { cnt = length; } if(copy_from_user(dev->disp_buf, buffer, cnt)) { dev_err(&dev->spi->dev, "oled_write: copy_from_user failed\n"); retval = -EFAULT; goto quit_write; } else { retval = cnt; } status = screen_buf_to_display(dev->disp_buf, dev); if(status) { dev_err(&dev->spi->dev, "oled_write: Error sending string to display\n"); retval = -EFAULT; goto quit_write; } quit_write: mutex_unlock(&dev->mutex); write_lock_err: return retval; }
static int gpio_pmodoled_spi_remove(struct spi_device *spi) { int status; struct gpio_pmodoled_device *dev; uint8_t wr_buf[10]; dev = (struct gpio_pmodoled_device *) spi->dev.platform_data; if (dev == NULL) { dev_err(&spi->dev, "spi_remove: Error fetch gpio_pmodoled_device struct\n"); return -EINVAL; } #ifdef CONFIG_PMODS_DEBUG printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Clearing Display\n", dev->name); #endif /* Clear Display */ memset(dev->disp_buf, 0, DISPLAY_BUF_SZ); status = screen_buf_to_display(dev->disp_buf, dev); /* Turn off display */ wr_buf[0] = OLED_DISPLAY_OFF; status = spi_write(spi, wr_buf, 1); if (status) dev_err(&spi->dev, "oled_spi_remove: Error writing to SPI device\n"); /* Turn off VCC (VBAT) */ gpio_set_value(dev->iVBAT, 1); msleep(100); /* TUrn off VDD Power */ gpio_set_value(dev->iVDD, 1); #ifdef CONFIG_PMODS_DEBUG printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Free GPIOs\n", dev->name); #endif { struct gpio gpio_pmodoled_ctrl[] = { {dev->iVBAT, GPIOF_OUT_INIT_HIGH, "OLED VBat"}, {dev->iVDD, GPIOF_OUT_INIT_HIGH, "OLED VDD"}, {dev->iRES, GPIOF_OUT_INIT_HIGH, "OLED_RESET"}, {dev->iDC, GPIOF_OUT_INIT_HIGH, "OLED_D/C"}, }; gpio_free_array(gpio_pmodoled_ctrl, 4); } if (&dev->cdev) { #ifdef CONFIG_PMODS_DEBUG printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Destroy Char Device\n", dev->name); #endif device_destroy(gpio_pmodoled_class, dev->dev_id); cdev_del(&dev->cdev); } cur_minor--; printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Device Removed\n", dev->name); return status; }
/** * SPI hardware probe. Sets correct SPI mode, attempts * to obtain memory needed by the driver, and performs * a simple initialization of the device. */ static int gpio_pmodoled_spi_probe(struct spi_device *spi) { int status = 0; struct gpio_pmodoled_device *gpio_pmodoled_dev; /* We rely on full duplex transfers, mostly to reduce * per transfer overheads (by making few transfers). */ if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) { status = -EINVAL; dev_err(&spi->dev, "SPI settings incorrect: %d\n", status); goto spi_err; } /* We must use SPI_MODE_0 */ spi->mode = SPI_MODE_0; spi->bits_per_word = 8; status = spi_setup(spi); if (status < 0) { dev_err(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n", spi->mode, spi->max_speed_hz / 1000, status); goto spi_err; } /* Get gpio_pmodoled_device structure */ gpio_pmodoled_dev = (struct gpio_pmodoled_device *) spi->dev.platform_data; if (gpio_pmodoled_dev == NULL) { dev_err(&spi->dev, "Cannot get gpio_pmodoled_device.\n"); status = -EINVAL; goto spi_platform_data_err; } printk(KERN_INFO SPI_DRIVER_NAME " [%s] SPI Probing\n", gpio_pmodoled_dev->name); #ifdef CONFIG_PMODS_DEBUG printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: setup char device\n", gpio_pmodoled_dev->name); #endif /* Setup char driver */ status = gpio_pmodoled_setup_cdev(gpio_pmodoled_dev, &(gpio_pmodoled_dev->dev_id), spi); if (status) { dev_err(&spi->dev, "spi_probe: Error adding %s device: %d\n", SPI_DRIVER_NAME, status); goto cdev_add_err; } /* Initialize Mutex */ mutex_init(&gpio_pmodoled_dev->mutex); /** * It is important to the OLED's longevity that the lines that * control it's power are carefully controlled. This is a good * time to ensure that the device is ot turned on until it is * instructed to do so. */ #ifdef CONFIG_PMODS_DEBUG printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: initialize device\n", gpio_pmodoled_dev->name); #endif status = gpio_pmodoled_init_gpio(gpio_pmodoled_dev); if (status) { dev_err(&spi->dev, "spi_probe: Error initializing GPIO\n"); goto oled_init_error; } gpio_pmodoled_disp_init(gpio_pmodoled_dev); memset(gpio_pmodoled_dev->disp_buf, 0x00, DISPLAY_BUF_SZ); status = screen_buf_to_display(gpio_pmodoled_dev->disp_buf, gpio_pmodoled_dev); if (status) { dev_err(&spi->dev, "spi_probe: Error sending initial Display String\n"); goto oled_init_error; } return status; oled_init_error: if (&gpio_pmodoled_dev->cdev) cdev_del(&gpio_pmodoled_dev->cdev); cdev_add_err: spi_platform_data_err: spi_err: return status; }