forked from Minki/linux
1802d0beec
Based on 1 normalized pattern(s): 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 655 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Richard Fontana <rfontana@redhat.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070034.575739538@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
154 lines
3.2 KiB
C
154 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Samsung LSI S5C73M3 8M pixel camera driver
|
|
*
|
|
* Copyright (C) 2012, Samsung Electronics, Co., Ltd.
|
|
* Sylwester Nawrocki <s.nawrocki@samsung.com>
|
|
* Andrzej Hajda <a.hajda@samsung.com>
|
|
*/
|
|
|
|
#include <linux/sizes.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/init.h>
|
|
#include <linux/media.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/spi/spi.h>
|
|
|
|
#include "s5c73m3.h"
|
|
|
|
#define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI"
|
|
|
|
static const struct of_device_id s5c73m3_spi_ids[] = {
|
|
{ .compatible = "samsung,s5c73m3" },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids);
|
|
|
|
enum spi_direction {
|
|
SPI_DIR_RX,
|
|
SPI_DIR_TX
|
|
};
|
|
|
|
static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
|
|
enum spi_direction dir)
|
|
{
|
|
struct spi_message msg;
|
|
int r;
|
|
struct spi_transfer xfer = {
|
|
.len = len,
|
|
};
|
|
|
|
if (dir == SPI_DIR_TX)
|
|
xfer.tx_buf = addr;
|
|
else
|
|
xfer.rx_buf = addr;
|
|
|
|
if (spi_dev == NULL) {
|
|
pr_err("SPI device is uninitialized\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
spi_message_init(&msg);
|
|
spi_message_add_tail(&xfer, &msg);
|
|
|
|
r = spi_sync(spi_dev, &msg);
|
|
if (r < 0)
|
|
dev_err(&spi_dev->dev, "%s spi_sync failed %d\n", __func__, r);
|
|
|
|
return r;
|
|
}
|
|
|
|
int s5c73m3_spi_write(struct s5c73m3 *state, const void *addr,
|
|
const unsigned int len, const unsigned int tx_size)
|
|
{
|
|
struct spi_device *spi_dev = state->spi_dev;
|
|
u32 count = len / tx_size;
|
|
u32 extra = len % tx_size;
|
|
unsigned int i, j = 0;
|
|
u8 padding[32];
|
|
int r = 0;
|
|
|
|
memset(padding, 0, sizeof(padding));
|
|
|
|
for (i = 0; i < count; i++) {
|
|
r = spi_xmit(spi_dev, (void *)addr + j, tx_size, SPI_DIR_TX);
|
|
if (r < 0)
|
|
return r;
|
|
j += tx_size;
|
|
}
|
|
|
|
if (extra > 0) {
|
|
r = spi_xmit(spi_dev, (void *)addr + j, extra, SPI_DIR_TX);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
return spi_xmit(spi_dev, padding, sizeof(padding), SPI_DIR_TX);
|
|
}
|
|
|
|
int s5c73m3_spi_read(struct s5c73m3 *state, void *addr,
|
|
const unsigned int len, const unsigned int tx_size)
|
|
{
|
|
struct spi_device *spi_dev = state->spi_dev;
|
|
u32 count = len / tx_size;
|
|
u32 extra = len % tx_size;
|
|
unsigned int i, j = 0;
|
|
int r = 0;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
r = spi_xmit(spi_dev, addr + j, tx_size, SPI_DIR_RX);
|
|
if (r < 0)
|
|
return r;
|
|
j += tx_size;
|
|
}
|
|
|
|
if (extra > 0)
|
|
return spi_xmit(spi_dev, addr + j, extra, SPI_DIR_RX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int s5c73m3_spi_probe(struct spi_device *spi)
|
|
{
|
|
int r;
|
|
struct s5c73m3 *state = container_of(spi->dev.driver, struct s5c73m3,
|
|
spidrv.driver);
|
|
spi->bits_per_word = 32;
|
|
|
|
r = spi_setup(spi);
|
|
if (r < 0) {
|
|
dev_err(&spi->dev, "spi_setup() failed\n");
|
|
return r;
|
|
}
|
|
|
|
mutex_lock(&state->lock);
|
|
state->spi_dev = spi;
|
|
mutex_unlock(&state->lock);
|
|
|
|
v4l2_info(&state->sensor_sd, "S5C73M3 SPI probed successfully\n");
|
|
return 0;
|
|
}
|
|
|
|
static int s5c73m3_spi_remove(struct spi_device *spi)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int s5c73m3_register_spi_driver(struct s5c73m3 *state)
|
|
{
|
|
struct spi_driver *spidrv = &state->spidrv;
|
|
|
|
spidrv->remove = s5c73m3_spi_remove;
|
|
spidrv->probe = s5c73m3_spi_probe;
|
|
spidrv->driver.name = S5C73M3_SPI_DRV_NAME;
|
|
spidrv->driver.of_match_table = s5c73m3_spi_ids;
|
|
|
|
return spi_register_driver(spidrv);
|
|
}
|
|
|
|
void s5c73m3_unregister_spi_driver(struct s5c73m3 *state)
|
|
{
|
|
spi_unregister_driver(&state->spidrv);
|
|
}
|