@@ -1,9 +1,9 @@
saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \
- saa7134-video.o saa7134-input.o
+ saa7134-video.o saa7134-input.o saa7134-spi.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o upd61151.o
obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
@@ -4619,6 +4619,7 @@
.name = name_radio,
.amux = LINE2,
},
+ .encoder_type = SAA7134_ENCODER_SAA6752HS,
.mpeg = SAA7134_MPEG_EMPRESS,
.video_out = CCIR656,
.vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
@@ -4656,6 +4657,7 @@
.name = name_radio,
.amux = LINE2,
},
+ .encoder_type = SAA7134_ENCODER_SAA6752HS,
.mpeg = SAA7134_MPEG_EMPRESS,
.video_out = CCIR656,
.vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
@@ -4695,6 +4697,7 @@
.name = name_radio,
.amux = LINE2,
},
+ .encoder_type = SAA7134_ENCODER_SAA6752HS,
.mpeg = SAA7134_MPEG_EMPRESS,
.video_out = CCIR656,
.vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
@@ -5279,23 +5282,43 @@
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x00860000,
.inputs = { {
.name = name_tv,
.vmux = 2,
.amux = TV,
.tv = 1,
- }, {
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE1,
+ .gpio = 0x00860000
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x00860000
}, {
.name = name_svideo,
.vmux = 9,
.amux = LINE1,
- } },
- .radio = {
- .name = name_radio,
- .amux = TV,
+ .gpio = 0x00860000
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00860000
+ },
+ .encoder_type = SAA7134_ENCODER_muPD61151,
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ .spi = {
+ .cs = 17,
+ .clock = 18,
+ .mosi = 23,
+ .miso = 21,
+ .num_chipselect = 1,
+ .spi_enable = 1,
},
},
[SAA7134_BOARD_ZOLID_HYBRID_PCI] = {
@@ -139,6 +139,18 @@
break;
}
}
+
+u32 saa7134_get_gpio(struct saa7134_dev *dev)
+{
+ unsigned long status;
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0);
+ saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN);
+ status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff;
+ return status;
+}
+
/* ------------------------------------------------------------------ */
@@ -1057,12 +1069,42 @@
saa7134_hwinit2(dev);
- /* load i2c helpers */
+ /* initialize software SPI bus */
+ if (saa7134_boards[dev->board].spi.spi_enable)
+ {
+ dev->spi = saa7134_boards[dev->board].spi;
+
+ /* register SPI master and SPI slave */
+ if (saa7134_spi_register(dev, &saa7134_boards[dev->board].spi_conf))
+ saa7134_boards[dev->board].spi.spi_enable = 0;
+ }
+
+ /* load bus helpers */
if (card_is_empress(dev)) {
- struct v4l2_subdev *sd =
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ struct v4l2_subdev *sd = NULL;
+
+ dev->encoder_type = saa7134_boards[dev->board].encoder_type;
+
+ switch (dev->encoder_type) {
+ case SAA7134_ENCODER_muPD61151:
+ {
+ printk(KERN_INFO "%s: found muPD61151 MPEG encoder\n", dev->name);
+
+ if (saa7134_boards[dev->board].spi.spi_enable)
+ sd = v4l2_spi_new_subdev(&dev->v4l2_dev, dev->spi_adap, &saa7134_boards[dev->board].spi_conf);
+ }
+ break;
+ case SAA7134_ENCODER_SAA6752HS:
+ {
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"saa6752hs", "saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);
+ }
+ break;
+ default:
+ printk(KERN_INFO "%s: MPEG encoder is not configured\n", dev->name);
+ break;
+ }
if (sd)
sd->grp_id = GRP_EMPRESS;
@@ -1139,6 +1181,8 @@
return 0;
fail4:
+ if ((card_is_empress(dev)) && (dev->encoder_type == SAA7134_ENCODER_muPD61151))
+ saa7134_spi_unregister(dev);
saa7134_unregister_video(dev);
saa7134_i2c_unregister(dev);
free_irq(pci_dev->irq, dev);
@@ -1412,6 +1456,7 @@
/* ----------------------------------------------------------- */
EXPORT_SYMBOL(saa7134_set_gpio);
+EXPORT_SYMBOL(saa7134_get_gpio);
EXPORT_SYMBOL(saa7134_boards);
/* ----------------- for the DMA sound modules --------------- */
@@ -30,6 +30,13 @@
#include <linux/notifier.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+
+/* ifdef software SPI insert here start */
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/spi/spi_bitbang.h>
+/* ifdef software SPI insert here stop */
#include <asm/io.h>
@@ -337,6 +344,21 @@
SAA7134_MPEG_TS_SERIAL,
};
+enum saa7134_encoder_type {
+ SAA7134_ENCODER_UNUSED,
+ SAA7134_ENCODER_SAA6752HS,
+ SAA7134_ENCODER_muPD61151,
+};
+
+struct saa7134_software_spi {
+ unsigned char cs:5;
+ unsigned char clock:5;
+ unsigned char mosi:5;
+ unsigned char miso:5;
+ unsigned char num_chipselect:3;
+ unsigned char spi_enable:1;
+};
+
struct saa7134_board {
char *name;
unsigned int audio_clock;
@@ -355,6 +377,10 @@
unsigned char empress_addr;
unsigned char rds_addr;
+ /* SPI info */
+ struct saa7134_software_spi spi;
+ struct spi_board_info spi_conf;
+
unsigned int tda9887_conf;
unsigned int tuner_config;
@@ -362,6 +388,7 @@
enum saa7134_video_out video_out;
enum saa7134_mpeg_type mpeg;
enum saa7134_mpeg_ts_type ts_type;
+ enum saa7134_encoder_type encoder_type;
unsigned int vid_port_opts;
unsigned int ts_force_val:1;
};
@@ -506,6 +533,12 @@
void (*signal_change)(struct saa7134_dev *dev);
};
+struct saa7134_spi_gpio {
+ struct spi_bitbang bitbang;
+ struct spi_master *master;
+ struct saa7134_dev *controller_data;
+};
+
/* global device status */
struct saa7134_dev {
struct list_head devlist;
@@ -553,6 +586,10 @@
struct i2c_client i2c_client;
unsigned char eedata[256];
int has_rds;
+
+ /* software spi */
+ struct saa7134_software_spi spi;
+ struct spi_master *spi_adap;
/* video overlay */
struct v4l2_framebuffer ovbuf;
@@ -615,6 +652,7 @@
atomic_t empress_users;
struct work_struct empress_workqueue;
int empress_started;
+ enum saa7134_encoder_type encoder_type;
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
@@ -681,6 +719,7 @@
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
+u32 saa7134_get_gpio(struct saa7134_dev *dev);
#define SAA7134_PGTABLE_SIZE 4096
@@ -726,6 +765,11 @@
int saa7134_i2c_register(struct saa7134_dev *dev);
int saa7134_i2c_unregister(struct saa7134_dev *dev);
+/* ----------------------------------------------------------- */
+/* saa7134-spi.c */
+
+int saa7134_spi_register(struct saa7134_dev *dev, struct spi_board_info *info);
+void saa7134_spi_unregister(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
/* saa7134-video.c */
@@ -51,6 +51,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -1069,6 +1070,66 @@
#endif /* defined(CONFIG_I2C) */
+//#if defined(CONFIG_SPI) || (defined(CONFIG_SPI_MODULE) && defined(MODULE)) + SPI_BITBANG
+
+/* Load an spi sub-device. */
+
+void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+ const struct v4l2_subdev_ops *ops)
+{
+ v4l2_subdev_init(sd, ops);
+ sd->flags |= V4L2_SUBDEV_FL_IS_SPI;
+ /* the owner is the same as the spi_device's driver owner */
+ sd->owner = spi->dev.driver->owner;
+ /* spi_device and v4l2_subdev point to one another */
+ v4l2_set_subdevdata(sd, spi);
+ spi_set_drvdata(spi, sd);
+ /* initialize name */
+ strlcpy(sd->name, spi->dev.driver->name, sizeof(sd->name));
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_subdev_init);
+
+struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+ struct spi_master *master, struct spi_board_info *info)
+{
+ struct v4l2_subdev *sd = NULL;
+ struct spi_device *spi = NULL;
+
+ BUG_ON(!v4l2_dev);
+
+ if (info->modalias)
+ request_module(info->modalias);
+
+ spi = spi_new_device(master,info);
+
+ if (spi == NULL || spi->dev.driver ==NULL)
+ goto error;
+
+ if (!try_module_get(spi->dev.driver->owner))
+ goto error;
+
+ sd = spi_get_drvdata(spi);
+
+ /* Register with the v4l2_device which increases the module's
+ use count as well. */
+ if (v4l2_device_register_subdev(v4l2_dev, sd))
+ sd = NULL;
+
+ /* Decrease the module use count to match the first try_module_get. */
+ module_put(spi->dev.driver->owner);
+
+error:
+ /* If we have a client but no subdev, then something went wrong and
+ we must unregister the client. */
+ if (spi && sd == NULL)
+ spi_unregister_device(spi);
+
+ return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_spi_new_subdev);
+
+//#endif /* defined(CONFIG_SPI) */
+
/* Clamp x to be between min and max, aligned to a multiple of 2^align. min
* and max don't have to be aligned, but there must be at least one valid
* value. E.g., min=17,max=31,align=4 is not allowed as there are no multiples
@@ -100,6 +100,14 @@
}
#endif
#endif
+/* FIXME: ADD if def's for SPI subdevices */
+ if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
+ struct spi_device *spi = v4l2_get_subdevdata(sd);
+
+ if (spi)
+ spi_unregister_device(spi);
+ }
+
}
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister);
@@ -278,6 +278,11 @@
/* module cs53132a: just ident 53132 */
V4L2_IDENT_CS53l32A = 53132,
+ /* modules upd61151 MPEG2 encoder: just ident 54000 */
+ V4L2_IDENT_UPD61161 = 54000,
+ /* modules upd61152 MPEG2 encoder with AC3: just ident 54001 */
+ V4L2_IDENT_UPD61162 = 54001,
+
/* module upd64031a: just ident 64031 */
V4L2_IDENT_UPD64031A = 64031,
@@ -191,6 +191,25 @@
/* ------------------------------------------------------------------------- */
+/* SPI Helper functions */
+
+#include <linux/spi/spi.h>
+
+struct spi_device_id;
+struct spi_device;
+
+/* Load an spi module and return an initialized v4l2_subdev struct.
+ Only call request_module if module_name != NULL.
+ The client_type argument is the name of the chip that's on the adapter. */
+struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
+ struct spi_master *master, struct spi_board_info *info);
+
+/* Initialize an v4l2_subdev with data from an spi_device struct */
+void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
+ const struct v4l2_subdev_ops *ops);
+
+/* ------------------------------------------------------------------------- */
+
/* Note: these remaining ioctls/structs should be removed as well, but they are
still used in tuner-simple.c (TUNER_SET_CONFIG), cx18/ivtv (RESET) and
v4l2-int-device.h (v4l2_routing). To remove these ioctls some more cleanup
@@ -387,6 +387,8 @@
/* Set this flag if this subdev is a i2c device. */
#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+/* Set this flag if this subdev is a spi device. */
+#define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
/* Each instance of a subdev driver should create this struct, either
stand-alone or embedded in a larger struct.