162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
462306a36Sopenharmony_ci * multifunction chip.  Currently works with the Omnivision OV7670
562306a36Sopenharmony_ci * sensor.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * The data sheet for this device can be found at:
862306a36Sopenharmony_ci *    http://wiki.laptop.org/images/5/5c/88ALP01_Datasheet_July_2007.pdf
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Copyright 2006-11 One Laptop Per Child Association, Inc.
1162306a36Sopenharmony_ci * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
1262306a36Sopenharmony_ci * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * Written by Jonathan Corbet, corbet@lwn.net.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * v4l2_device/v4l2_subdev conversion by:
1762306a36Sopenharmony_ci * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/init.h>
2262306a36Sopenharmony_ci#include <linux/pci.h>
2362306a36Sopenharmony_ci#include <linux/i2c.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/spinlock.h>
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci#include <linux/videodev2.h>
2862306a36Sopenharmony_ci#include <media/v4l2-device.h>
2962306a36Sopenharmony_ci#include <media/i2c/ov7670.h>
3062306a36Sopenharmony_ci#include <linux/device.h>
3162306a36Sopenharmony_ci#include <linux/wait.h>
3262306a36Sopenharmony_ci#include <linux/delay.h>
3362306a36Sopenharmony_ci#include <linux/io.h>
3462306a36Sopenharmony_ci#include <linux/clkdev.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "mcam-core.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define CAFE_VERSION 0x000002
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Parameters.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ciMODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
4562306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
4662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct cafe_camera {
4962306a36Sopenharmony_ci	int registered;			/* Fully initialized? */
5062306a36Sopenharmony_ci	struct mcam_camera mcam;
5162306a36Sopenharmony_ci	struct pci_dev *pdev;
5262306a36Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
5362306a36Sopenharmony_ci	wait_queue_head_t smbus_wait;	/* Waiting on i2c events */
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * Most of the camera controller registers are defined in mcam-core.h,
5862306a36Sopenharmony_ci * but the Cafe platform has some additional registers of its own;
5962306a36Sopenharmony_ci * they are described here.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * "General purpose register" has a couple of GPIOs used for sensor
6462306a36Sopenharmony_ci * power and reset on OLPC XO 1.0 systems.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci#define REG_GPR		0xb4
6762306a36Sopenharmony_ci#define	  GPR_C1EN	  0x00000020	/* Pad 1 (power down) enable */
6862306a36Sopenharmony_ci#define	  GPR_C0EN	  0x00000010	/* Pad 0 (reset) enable */
6962306a36Sopenharmony_ci#define	  GPR_C1	  0x00000002	/* Control 1 value */
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
7262306a36Sopenharmony_ci * it is active low.
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_ci#define	  GPR_C0	  0x00000001	/* Control 0 value */
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/*
7762306a36Sopenharmony_ci * These registers control the SMBUS module for communicating
7862306a36Sopenharmony_ci * with the sensor.
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci#define REG_TWSIC0	0xb8	/* TWSI (smbus) control 0 */
8162306a36Sopenharmony_ci#define	  TWSIC0_EN	  0x00000001	/* TWSI enable */
8262306a36Sopenharmony_ci#define	  TWSIC0_MODE	  0x00000002	/* 1 = 16-bit, 0 = 8-bit */
8362306a36Sopenharmony_ci#define	  TWSIC0_SID	  0x000003fc	/* Slave ID */
8462306a36Sopenharmony_ci/*
8562306a36Sopenharmony_ci * Subtle trickery: the slave ID field starts with bit 2.  But the
8662306a36Sopenharmony_ci * Linux i2c stack wants to treat the bottommost bit as a separate
8762306a36Sopenharmony_ci * read/write bit, which is why slave ID's are usually presented
8862306a36Sopenharmony_ci * >>1.  For consistency with that behavior, we shift over three
8962306a36Sopenharmony_ci * bits instead of two.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_ci#define	  TWSIC0_SID_SHIFT 3
9262306a36Sopenharmony_ci#define	  TWSIC0_CLKDIV	  0x0007fc00	/* Clock divider */
9362306a36Sopenharmony_ci#define	  TWSIC0_MASKACK  0x00400000	/* Mask ack from sensor */
9462306a36Sopenharmony_ci#define	  TWSIC0_OVMAGIC  0x00800000	/* Make it work on OV sensors */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define REG_TWSIC1	0xbc	/* TWSI control 1 */
9762306a36Sopenharmony_ci#define	  TWSIC1_DATA	  0x0000ffff	/* Data to/from camchip */
9862306a36Sopenharmony_ci#define	  TWSIC1_ADDR	  0x00ff0000	/* Address (register) */
9962306a36Sopenharmony_ci#define	  TWSIC1_ADDR_SHIFT 16
10062306a36Sopenharmony_ci#define	  TWSIC1_READ	  0x01000000	/* Set for read op */
10162306a36Sopenharmony_ci#define	  TWSIC1_WSTAT	  0x02000000	/* Write status */
10262306a36Sopenharmony_ci#define	  TWSIC1_RVALID	  0x04000000	/* Read data valid */
10362306a36Sopenharmony_ci#define	  TWSIC1_ERROR	  0x08000000	/* Something screwed up */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * Here's the weird global control registers
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_ci#define REG_GL_CSR     0x3004  /* Control/status register */
10962306a36Sopenharmony_ci#define	  GCSR_SRS	 0x00000001	/* SW Reset set */
11062306a36Sopenharmony_ci#define	  GCSR_SRC	 0x00000002	/* SW Reset clear */
11162306a36Sopenharmony_ci#define	  GCSR_MRS	 0x00000004	/* Master reset set */
11262306a36Sopenharmony_ci#define	  GCSR_MRC	 0x00000008	/* HW Reset clear */
11362306a36Sopenharmony_ci#define	  GCSR_CCIC_EN	 0x00004000    /* CCIC Clock enable */
11462306a36Sopenharmony_ci#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
11562306a36Sopenharmony_ci#define	  GIMSK_CCIC_EN		 0x00000004    /* CCIC Interrupt enable */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define REG_GL_FCR	0x3038	/* GPIO functional control register */
11862306a36Sopenharmony_ci#define	  GFCR_GPIO_ON	  0x08		/* Camera GPIO enabled */
11962306a36Sopenharmony_ci#define REG_GL_GPIOR	0x315c	/* GPIO register */
12062306a36Sopenharmony_ci#define	  GGPIO_OUT		0x80000	/* GPIO output */
12162306a36Sopenharmony_ci#define	  GGPIO_VAL		0x00008	/* Output pin value */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define REG_LEN		       (REG_GL_IMASK + 4)
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci * Debugging and related.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_ci#define cam_err(cam, fmt, arg...) \
13062306a36Sopenharmony_ci	dev_err(&(cam)->pdev->dev, fmt, ##arg);
13162306a36Sopenharmony_ci#define cam_warn(cam, fmt, arg...) \
13262306a36Sopenharmony_ci	dev_warn(&(cam)->pdev->dev, fmt, ##arg);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
13562306a36Sopenharmony_ci/*
13662306a36Sopenharmony_ci * The I2C/SMBUS interface to the camera itself starts here.  The
13762306a36Sopenharmony_ci * controller handles SMBUS itself, presenting a relatively simple register
13862306a36Sopenharmony_ci * interface; all we have to do is to tell it where to route the data.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_ci#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int cafe_smbus_write_done(struct mcam_camera *mcam)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	unsigned long flags;
14562306a36Sopenharmony_ci	int c1;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * We must delay after the interrupt, or the controller gets confused
14962306a36Sopenharmony_ci	 * and never does give us good status.  Fortunately, we don't do this
15062306a36Sopenharmony_ci	 * often.
15162306a36Sopenharmony_ci	 */
15262306a36Sopenharmony_ci	udelay(20);
15362306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
15462306a36Sopenharmony_ci	c1 = mcam_reg_read(mcam, REG_TWSIC1);
15562306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
15662306a36Sopenharmony_ci	return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic int cafe_smbus_write_data(struct cafe_camera *cam,
16062306a36Sopenharmony_ci		u16 addr, u8 command, u8 value)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	unsigned int rval;
16362306a36Sopenharmony_ci	unsigned long flags;
16462306a36Sopenharmony_ci	struct mcam_camera *mcam = &cam->mcam;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
16762306a36Sopenharmony_ci	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
16862306a36Sopenharmony_ci	rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
16962306a36Sopenharmony_ci	/*
17062306a36Sopenharmony_ci	 * Marvell sez set clkdiv to all 1's for now.
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	rval |= TWSIC0_CLKDIV;
17362306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_TWSIC0, rval);
17462306a36Sopenharmony_ci	(void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
17562306a36Sopenharmony_ci	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
17662306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_TWSIC1, rval);
17762306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Unfortunately, reading TWSIC1 too soon after sending a command
18062306a36Sopenharmony_ci	 * causes the device to die.
18162306a36Sopenharmony_ci	 * Use a busy-wait because we often send a large quantity of small
18262306a36Sopenharmony_ci	 * commands at-once; using msleep() would cause a lot of context
18362306a36Sopenharmony_ci	 * switches which take longer than 2ms, resulting in a noticeable
18462306a36Sopenharmony_ci	 * boot-time and capture-start delays.
18562306a36Sopenharmony_ci	 */
18662306a36Sopenharmony_ci	mdelay(2);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/*
18962306a36Sopenharmony_ci	 * Another sad fact is that sometimes, commands silently complete but
19062306a36Sopenharmony_ci	 * cafe_smbus_write_done() never becomes aware of this.
19162306a36Sopenharmony_ci	 * This happens at random and appears to possible occur with any
19262306a36Sopenharmony_ci	 * command.
19362306a36Sopenharmony_ci	 * We don't understand why this is. We work around this issue
19462306a36Sopenharmony_ci	 * with the timeout in the wait below, assuming that all commands
19562306a36Sopenharmony_ci	 * complete within the timeout.
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam),
19862306a36Sopenharmony_ci			CAFE_SMBUS_TIMEOUT);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
20162306a36Sopenharmony_ci	rval = mcam_reg_read(mcam, REG_TWSIC1);
20262306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (rval & TWSIC1_WSTAT) {
20562306a36Sopenharmony_ci		cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
20662306a36Sopenharmony_ci				command, value);
20762306a36Sopenharmony_ci		return -EIO;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	if (rval & TWSIC1_ERROR) {
21062306a36Sopenharmony_ci		cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
21162306a36Sopenharmony_ci				command, value);
21262306a36Sopenharmony_ci		return -EIO;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	return 0;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int cafe_smbus_read_done(struct mcam_camera *mcam)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	unsigned long flags;
22262306a36Sopenharmony_ci	int c1;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * We must delay after the interrupt, or the controller gets confused
22662306a36Sopenharmony_ci	 * and never does give us good status.  Fortunately, we don't do this
22762306a36Sopenharmony_ci	 * often.
22862306a36Sopenharmony_ci	 */
22962306a36Sopenharmony_ci	udelay(20);
23062306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
23162306a36Sopenharmony_ci	c1 = mcam_reg_read(mcam, REG_TWSIC1);
23262306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
23362306a36Sopenharmony_ci	return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int cafe_smbus_read_data(struct cafe_camera *cam,
23962306a36Sopenharmony_ci		u16 addr, u8 command, u8 *value)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	unsigned int rval;
24262306a36Sopenharmony_ci	unsigned long flags;
24362306a36Sopenharmony_ci	struct mcam_camera *mcam = &cam->mcam;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
24662306a36Sopenharmony_ci	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
24762306a36Sopenharmony_ci	rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * Marvel sez set clkdiv to all 1's for now.
25062306a36Sopenharmony_ci	 */
25162306a36Sopenharmony_ci	rval |= TWSIC0_CLKDIV;
25262306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_TWSIC0, rval);
25362306a36Sopenharmony_ci	(void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
25462306a36Sopenharmony_ci	rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
25562306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_TWSIC1, rval);
25662306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	wait_event_timeout(cam->smbus_wait,
25962306a36Sopenharmony_ci			cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT);
26062306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
26162306a36Sopenharmony_ci	rval = mcam_reg_read(mcam, REG_TWSIC1);
26262306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (rval & TWSIC1_ERROR) {
26562306a36Sopenharmony_ci		cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
26662306a36Sopenharmony_ci		return -EIO;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	if (!(rval & TWSIC1_RVALID)) {
26962306a36Sopenharmony_ci		cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
27062306a36Sopenharmony_ci				command);
27162306a36Sopenharmony_ci		return -EIO;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	*value = rval & 0xff;
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/*
27862306a36Sopenharmony_ci * Perform a transfer over SMBUS.  This thing is called under
27962306a36Sopenharmony_ci * the i2c bus lock, so we shouldn't race with ourselves...
28062306a36Sopenharmony_ci */
28162306a36Sopenharmony_cistatic int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
28262306a36Sopenharmony_ci		unsigned short flags, char rw, u8 command,
28362306a36Sopenharmony_ci		int size, union i2c_smbus_data *data)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct cafe_camera *cam = i2c_get_adapdata(adapter);
28662306a36Sopenharmony_ci	int ret = -EINVAL;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/*
28962306a36Sopenharmony_ci	 * This interface would appear to only do byte data ops.  OK
29062306a36Sopenharmony_ci	 * it can do word too, but the cam chip has no use for that.
29162306a36Sopenharmony_ci	 */
29262306a36Sopenharmony_ci	if (size != I2C_SMBUS_BYTE_DATA) {
29362306a36Sopenharmony_ci		cam_err(cam, "funky xfer size %d\n", size);
29462306a36Sopenharmony_ci		return -EINVAL;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (rw == I2C_SMBUS_WRITE)
29862306a36Sopenharmony_ci		ret = cafe_smbus_write_data(cam, addr, command, data->byte);
29962306a36Sopenharmony_ci	else if (rw == I2C_SMBUS_READ)
30062306a36Sopenharmony_ci		ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
30162306a36Sopenharmony_ci	return ret;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic void cafe_smbus_enable_irq(struct cafe_camera *cam)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	unsigned long flags;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	spin_lock_irqsave(&cam->mcam.dev_lock, flags);
31062306a36Sopenharmony_ci	mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS);
31162306a36Sopenharmony_ci	spin_unlock_irqrestore(&cam->mcam.dev_lock, flags);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic u32 cafe_smbus_func(struct i2c_adapter *adapter)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
31762306a36Sopenharmony_ci	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic const struct i2c_algorithm cafe_smbus_algo = {
32162306a36Sopenharmony_ci	.smbus_xfer = cafe_smbus_xfer,
32262306a36Sopenharmony_ci	.functionality = cafe_smbus_func
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int cafe_smbus_setup(struct cafe_camera *cam)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct i2c_adapter *adap;
32862306a36Sopenharmony_ci	int ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
33162306a36Sopenharmony_ci	if (adap == NULL)
33262306a36Sopenharmony_ci		return -ENOMEM;
33362306a36Sopenharmony_ci	adap->owner = THIS_MODULE;
33462306a36Sopenharmony_ci	adap->algo = &cafe_smbus_algo;
33562306a36Sopenharmony_ci	strscpy(adap->name, "cafe_ccic", sizeof(adap->name));
33662306a36Sopenharmony_ci	adap->dev.parent = &cam->pdev->dev;
33762306a36Sopenharmony_ci	i2c_set_adapdata(adap, cam);
33862306a36Sopenharmony_ci	ret = i2c_add_adapter(adap);
33962306a36Sopenharmony_ci	if (ret) {
34062306a36Sopenharmony_ci		printk(KERN_ERR "Unable to register cafe i2c adapter\n");
34162306a36Sopenharmony_ci		kfree(adap);
34262306a36Sopenharmony_ci		return ret;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	cam->i2c_adapter = adap;
34662306a36Sopenharmony_ci	cafe_smbus_enable_irq(cam);
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic void cafe_smbus_shutdown(struct cafe_camera *cam)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	i2c_del_adapter(cam->i2c_adapter);
35362306a36Sopenharmony_ci	kfree(cam->i2c_adapter);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci/*
35862306a36Sopenharmony_ci * Controller-level stuff
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void cafe_ctlr_init(struct mcam_camera *mcam)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	unsigned long flags;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * Added magic to bring up the hardware on the B-Test board
36862306a36Sopenharmony_ci	 */
36962306a36Sopenharmony_ci	mcam_reg_write(mcam, 0x3038, 0x8);
37062306a36Sopenharmony_ci	mcam_reg_write(mcam, 0x315c, 0x80008);
37162306a36Sopenharmony_ci	/*
37262306a36Sopenharmony_ci	 * Go through the dance needed to wake the device up.
37362306a36Sopenharmony_ci	 * Note that these registers are global and shared
37462306a36Sopenharmony_ci	 * with the NAND and SD devices.  Interaction between the
37562306a36Sopenharmony_ci	 * three still needs to be examined.
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
37862306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
37962306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
38062306a36Sopenharmony_ci	/*
38162306a36Sopenharmony_ci	 * Here we must wait a bit for the controller to come around.
38262306a36Sopenharmony_ci	 */
38362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
38462306a36Sopenharmony_ci	msleep(5);
38562306a36Sopenharmony_ci	spin_lock_irqsave(&mcam->dev_lock, flags);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
38862306a36Sopenharmony_ci	mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN);
38962306a36Sopenharmony_ci	/*
39062306a36Sopenharmony_ci	 * Mask all interrupts.
39162306a36Sopenharmony_ci	 */
39262306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_IRQMASK, 0);
39362306a36Sopenharmony_ci	spin_unlock_irqrestore(&mcam->dev_lock, flags);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic int cafe_ctlr_power_up(struct mcam_camera *mcam)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	/*
40062306a36Sopenharmony_ci	 * Part one of the sensor dance: turn the global
40162306a36Sopenharmony_ci	 * GPIO signal on.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
40462306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
40562306a36Sopenharmony_ci	/*
40662306a36Sopenharmony_ci	 * Put the sensor into operational mode (assumes OLPC-style
40762306a36Sopenharmony_ci	 * wiring).  Control 0 is reset - set to 1 to operate.
40862306a36Sopenharmony_ci	 * Control 1 is power down, set to 0 to operate.
40962306a36Sopenharmony_ci	 */
41062306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
41162306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic void cafe_ctlr_power_down(struct mcam_camera *mcam)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
41962306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
42062306a36Sopenharmony_ci	mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci/*
42662306a36Sopenharmony_ci * The platform interrupt handler.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic irqreturn_t cafe_irq(int irq, void *data)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct cafe_camera *cam = data;
43162306a36Sopenharmony_ci	struct mcam_camera *mcam = &cam->mcam;
43262306a36Sopenharmony_ci	unsigned int irqs, handled;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	spin_lock(&mcam->dev_lock);
43562306a36Sopenharmony_ci	irqs = mcam_reg_read(mcam, REG_IRQSTAT);
43662306a36Sopenharmony_ci	handled = cam->registered && mccic_irq(mcam, irqs);
43762306a36Sopenharmony_ci	if (irqs & TWSIIRQS) {
43862306a36Sopenharmony_ci		mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS);
43962306a36Sopenharmony_ci		wake_up(&cam->smbus_wait);
44062306a36Sopenharmony_ci		handled = 1;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	spin_unlock(&mcam->dev_lock);
44362306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic struct ov7670_config sensor_cfg = {
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * Exclude QCIF mode, because it only captures a tiny portion
45162306a36Sopenharmony_ci	 * of the sensor FOV
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	.min_width = 320,
45462306a36Sopenharmony_ci	.min_height = 240,
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/*
45762306a36Sopenharmony_ci	 * Set the clock speed for the XO 1; I don't believe this
45862306a36Sopenharmony_ci	 * driver has ever run anywhere else.
45962306a36Sopenharmony_ci	 */
46062306a36Sopenharmony_ci	.clock_speed = 45,
46162306a36Sopenharmony_ci	.use_smbus = 1,
46262306a36Sopenharmony_ci};
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic struct i2c_board_info ov7670_info = {
46562306a36Sopenharmony_ci	.type = "ov7670",
46662306a36Sopenharmony_ci	.addr = 0x42 >> 1,
46762306a36Sopenharmony_ci	.platform_data = &sensor_cfg,
46862306a36Sopenharmony_ci};
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/* -------------------------------------------------------------------------- */
47162306a36Sopenharmony_ci/*
47262306a36Sopenharmony_ci * PCI interface stuff.
47362306a36Sopenharmony_ci */
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int cafe_pci_probe(struct pci_dev *pdev,
47662306a36Sopenharmony_ci		const struct pci_device_id *id)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	int ret;
47962306a36Sopenharmony_ci	struct cafe_camera *cam;
48062306a36Sopenharmony_ci	struct mcam_camera *mcam;
48162306a36Sopenharmony_ci	struct v4l2_async_connection *asd;
48262306a36Sopenharmony_ci	struct i2c_client *i2c_dev;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * Start putting together one of our big camera structures.
48662306a36Sopenharmony_ci	 */
48762306a36Sopenharmony_ci	ret = -ENOMEM;
48862306a36Sopenharmony_ci	cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
48962306a36Sopenharmony_ci	if (cam == NULL)
49062306a36Sopenharmony_ci		goto out;
49162306a36Sopenharmony_ci	pci_set_drvdata(pdev, cam);
49262306a36Sopenharmony_ci	cam->pdev = pdev;
49362306a36Sopenharmony_ci	mcam = &cam->mcam;
49462306a36Sopenharmony_ci	mcam->chip_id = MCAM_CAFE;
49562306a36Sopenharmony_ci	spin_lock_init(&mcam->dev_lock);
49662306a36Sopenharmony_ci	init_waitqueue_head(&cam->smbus_wait);
49762306a36Sopenharmony_ci	mcam->plat_power_up = cafe_ctlr_power_up;
49862306a36Sopenharmony_ci	mcam->plat_power_down = cafe_ctlr_power_down;
49962306a36Sopenharmony_ci	mcam->dev = &pdev->dev;
50062306a36Sopenharmony_ci	/*
50162306a36Sopenharmony_ci	 * Vmalloc mode for buffers is traditional with this driver.
50262306a36Sopenharmony_ci	 * We *might* be able to run DMA_contig, especially on a system
50362306a36Sopenharmony_ci	 * with CMA in it.
50462306a36Sopenharmony_ci	 */
50562306a36Sopenharmony_ci	mcam->buffer_mode = B_vmalloc;
50662306a36Sopenharmony_ci	/*
50762306a36Sopenharmony_ci	 * Get set up on the PCI bus.
50862306a36Sopenharmony_ci	 */
50962306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
51062306a36Sopenharmony_ci	if (ret)
51162306a36Sopenharmony_ci		goto out_free;
51262306a36Sopenharmony_ci	pci_set_master(pdev);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ret = -EIO;
51562306a36Sopenharmony_ci	mcam->regs = pci_iomap(pdev, 0, 0);
51662306a36Sopenharmony_ci	if (!mcam->regs) {
51762306a36Sopenharmony_ci		printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
51862306a36Sopenharmony_ci		goto out_disable;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci	mcam->regs_size = pci_resource_len(pdev, 0);
52162306a36Sopenharmony_ci	ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
52262306a36Sopenharmony_ci	if (ret)
52362306a36Sopenharmony_ci		goto out_iounmap;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/*
52662306a36Sopenharmony_ci	 * Initialize the controller.
52762306a36Sopenharmony_ci	 */
52862306a36Sopenharmony_ci	cafe_ctlr_init(mcam);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/*
53162306a36Sopenharmony_ci	 * Set up I2C/SMBUS communications.  We have to drop the mutex here
53262306a36Sopenharmony_ci	 * because the sensor could attach in this call chain, leading to
53362306a36Sopenharmony_ci	 * unsightly deadlocks.
53462306a36Sopenharmony_ci	 */
53562306a36Sopenharmony_ci	ret = cafe_smbus_setup(cam);
53662306a36Sopenharmony_ci	if (ret)
53762306a36Sopenharmony_ci		goto out_pdown;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	ret = v4l2_device_register(mcam->dev, &mcam->v4l2_dev);
54062306a36Sopenharmony_ci	if (ret)
54162306a36Sopenharmony_ci		goto out_smbus_shutdown;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	v4l2_async_nf_init(&mcam->notifier, &mcam->v4l2_dev);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	asd = v4l2_async_nf_add_i2c(&mcam->notifier,
54662306a36Sopenharmony_ci				    i2c_adapter_id(cam->i2c_adapter),
54762306a36Sopenharmony_ci				    ov7670_info.addr,
54862306a36Sopenharmony_ci				    struct v4l2_async_connection);
54962306a36Sopenharmony_ci	if (IS_ERR(asd)) {
55062306a36Sopenharmony_ci		ret = PTR_ERR(asd);
55162306a36Sopenharmony_ci		goto out_v4l2_device_unregister;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	ret = mccic_register(mcam);
55562306a36Sopenharmony_ci	if (ret)
55662306a36Sopenharmony_ci		goto out_v4l2_device_unregister;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	clkdev_create(mcam->mclk, "xclk", "%d-%04x",
55962306a36Sopenharmony_ci		i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	i2c_dev = i2c_new_client_device(cam->i2c_adapter, &ov7670_info);
56262306a36Sopenharmony_ci	if (IS_ERR(i2c_dev)) {
56362306a36Sopenharmony_ci		ret = PTR_ERR(i2c_dev);
56462306a36Sopenharmony_ci		goto out_mccic_shutdown;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	cam->registered = 1;
56862306a36Sopenharmony_ci	return 0;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ciout_mccic_shutdown:
57162306a36Sopenharmony_ci	mccic_shutdown(mcam);
57262306a36Sopenharmony_ciout_v4l2_device_unregister:
57362306a36Sopenharmony_ci	v4l2_device_unregister(&mcam->v4l2_dev);
57462306a36Sopenharmony_ciout_smbus_shutdown:
57562306a36Sopenharmony_ci	cafe_smbus_shutdown(cam);
57662306a36Sopenharmony_ciout_pdown:
57762306a36Sopenharmony_ci	cafe_ctlr_power_down(mcam);
57862306a36Sopenharmony_ci	free_irq(pdev->irq, cam);
57962306a36Sopenharmony_ciout_iounmap:
58062306a36Sopenharmony_ci	pci_iounmap(pdev, mcam->regs);
58162306a36Sopenharmony_ciout_disable:
58262306a36Sopenharmony_ci	pci_disable_device(pdev);
58362306a36Sopenharmony_ciout_free:
58462306a36Sopenharmony_ci	kfree(cam);
58562306a36Sopenharmony_ciout:
58662306a36Sopenharmony_ci	return ret;
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/*
59162306a36Sopenharmony_ci * Shut down an initialized device
59262306a36Sopenharmony_ci */
59362306a36Sopenharmony_cistatic void cafe_shutdown(struct cafe_camera *cam)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	mccic_shutdown(&cam->mcam);
59662306a36Sopenharmony_ci	v4l2_device_unregister(&cam->mcam.v4l2_dev);
59762306a36Sopenharmony_ci	cafe_smbus_shutdown(cam);
59862306a36Sopenharmony_ci	free_irq(cam->pdev->irq, cam);
59962306a36Sopenharmony_ci	pci_iounmap(cam->pdev, cam->mcam.regs);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void cafe_pci_remove(struct pci_dev *pdev)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct cafe_camera *cam = pci_get_drvdata(pdev);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (cam == NULL) {
60862306a36Sopenharmony_ci		printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
60962306a36Sopenharmony_ci		return;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci	cafe_shutdown(cam);
61262306a36Sopenharmony_ci	kfree(cam);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/*
61762306a36Sopenharmony_ci * Basic power management.
61862306a36Sopenharmony_ci */
61962306a36Sopenharmony_cistatic int __maybe_unused cafe_pci_suspend(struct device *dev)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct cafe_camera *cam = dev_get_drvdata(dev);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	mccic_suspend(&cam->mcam);
62462306a36Sopenharmony_ci	return 0;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic int __maybe_unused cafe_pci_resume(struct device *dev)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	struct cafe_camera *cam = dev_get_drvdata(dev);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	cafe_ctlr_init(&cam->mcam);
63362306a36Sopenharmony_ci	return mccic_resume(&cam->mcam);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic const struct pci_device_id cafe_ids[] = {
63762306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
63862306a36Sopenharmony_ci		     PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
63962306a36Sopenharmony_ci	{ 0, }
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cafe_ids);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(cafe_pci_pm_ops, cafe_pci_suspend, cafe_pci_resume);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic struct pci_driver cafe_pci_driver = {
64762306a36Sopenharmony_ci	.name = "cafe1000-ccic",
64862306a36Sopenharmony_ci	.id_table = cafe_ids,
64962306a36Sopenharmony_ci	.probe = cafe_pci_probe,
65062306a36Sopenharmony_ci	.remove = cafe_pci_remove,
65162306a36Sopenharmony_ci	.driver.pm = &cafe_pci_pm_ops,
65262306a36Sopenharmony_ci};
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int __init cafe_init(void)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	int ret;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
66262306a36Sopenharmony_ci			CAFE_VERSION);
66362306a36Sopenharmony_ci	ret = pci_register_driver(&cafe_pci_driver);
66462306a36Sopenharmony_ci	if (ret) {
66562306a36Sopenharmony_ci		printk(KERN_ERR "Unable to register cafe_ccic driver\n");
66662306a36Sopenharmony_ci		goto out;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	ret = 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ciout:
67162306a36Sopenharmony_ci	return ret;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic void __exit cafe_exit(void)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	pci_unregister_driver(&cafe_pci_driver);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cimodule_init(cafe_init);
68162306a36Sopenharmony_cimodule_exit(cafe_exit);
682