예제 #1
0
/**
 * 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;
}
예제 #2
0
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;
}
예제 #3
0
/**
 * 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;
}