From patchwork Mon Feb 2 08:06:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kassey Lee X-Patchwork-Id: 28116 X-Patchwork-Delegate: g.liakhovetski@gmx.de Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.72) (envelope-from ) id 1YIC20-0003KM-FK; Mon, 02 Feb 2015 09:06:52 +0100 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.72/mailfrontend-6) with esmtp id 1YIC1y-0005C6-3o; Mon, 02 Feb 2015 09:06:51 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932798AbbBBIGr (ORCPT + 1 other); Mon, 2 Feb 2015 03:06:47 -0500 Received: from mail-pa0-f50.google.com ([209.85.220.50]:55559 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753018AbbBBIGr (ORCPT ); Mon, 2 Feb 2015 03:06:47 -0500 Received: by mail-pa0-f50.google.com with SMTP id rd3so79283877pab.9 for ; Mon, 02 Feb 2015 00:06:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=DB4rqHzAQaGctUdiXvUADLoyJngGnhXFpA6nq35M9Wg=; b=zuSjG6mUAImY523QkiNqTPs8T1lWOsZSxpJ8Uh4t63EPlJzBw1ITLKe6vmi436E3qe tB7UMjG3qF5I5/MAwl6UFSZzekkSRJIia+cnJDNn79W+hw6lI+u3ODeOMDbFp9qv//rk /+NHx4WACZ0j4i8Dakphhh2PNVnDpZkCN/N5EAScvdfGSPRt7OQmKZkMKFqLNcaGNja+ 3cUEvbmjsxGFwkE1kWjDj5jGRLq41z/ctdTiSq+/28En6vmOFD3q2spNFPBBa4L6qsPt OsqcA81yuD9bvVPMNwT0bEXlEMl9OH+ai20GV5pdlcJ1JAFYfpXXTCJPQHEzm8rG8JnC yQYg== X-Received: by 10.66.65.195 with SMTP id z3mr27800462pas.10.1422864406444; Mon, 02 Feb 2015 00:06:46 -0800 (PST) Received: from kassey-System-Product-Name.nvidia.com ([203.18.50.4]) by mx.google.com with ESMTPSA id ge7sm6762269pbc.16.2015.02.02.00.06.43 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 02 Feb 2015 00:06:45 -0800 (PST) From: Kassey Li To: g.liakhovetski@gmx.de Cc: linux-media@vger.kernel.org, kasseyl@nvidia.com Subject: [PATCH V2] [media] V4L: soc-camera: add SPI device support Date: Mon, 2 Feb 2015 16:06:57 +0800 Message-Id: <1422864417-7296-1-git-send-email-kassey1216@gmail.com> X-Mailer: git-send-email 1.7.9.5 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 6.0.0.2142326, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2015.2.2.75719 X-PMX-Spam: Gauge=IIIIIIIII, Probability=9%, Report=' FORGED_FROM_GMAIL 0.1, MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_5000_5999 0, BODY_SIZE_7000_LESS 0, DKIM_SIGNATURE 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __CP_URI_IN_BODY 0, __DATE_TZ_HK 0, __FRAUD_WEBMAIL 0, __FRAUD_WEBMAIL_FROM 0, __FROM_GMAIL 0, __HAS_FROM 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __MIME_TEXT_ONLY 0, __MULTIPLE_RCPTS_CC_X2 0, __PHISH_SPEAR_STRUCTURE_1 0, __SANE_MSGID 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_NO_WWW 0, __URI_NS , __YOUTUBE_RCVD 0' From: Kassey Li This adds support for spi interface sub device for soc_camera. Signed-off-by: Kassey Li --- drivers/media/platform/soc_camera/soc_camera.c | 94 ++++++++++++++++++++++++ include/media/soc_camera.h | 4 + 2 files changed, 98 insertions(+) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index b3db51c..b01c075 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1430,6 +1431,91 @@ static void soc_camera_i2c_free(struct soc_camera_device *icd) icd->clk = NULL; } +static int soc_camera_spi_init(struct soc_camera_device *icd, + struct soc_camera_desc *sdesc) +{ + struct soc_camera_subdev_desc *ssdd; + struct spi_device *spi; + struct soc_camera_host *ici; + struct soc_camera_host_desc *shd = &sdesc->host_desc; + struct spi_master *spi_master; + struct v4l2_subdev *subdev; + char clk_name[V4L2_SUBDEV_NAME_SIZE]; + int ret; + + /* First find out how we link the main client */ + if (icd->sasc) { + /* Async non-OF probing handled by the subdevice list */ + return -EPROBE_DEFER; + } + + ici = to_soc_camera_host(icd->parent); + spi_master = spi_busnum_to_master(shd->spi_bus_id); + if (!spi_master) { + dev_err(icd->pdev, "Cannot get SPI master #%d. No driver?\n", + shd->spi_bus_id); + return -ENODEV; + } + + ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL); + if (!ssdd) + return -ENOMEM; + /* + * In synchronous case we request regulators ourselves in + * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try + * to allocate them again. + */ + ssdd->sd_pdata.num_regulators = 0; + ssdd->sd_pdata.regulators = NULL; + shd->board_info_spi->platform_data = ssdd; + + snprintf(clk_name, sizeof(clk_name), "%d", + shd->spi_bus_id); + + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + if (IS_ERR(icd->clk)) { + ret = PTR_ERR(icd->clk); + goto eclkreg; + } + + subdev = v4l2_spi_new_subdev(&ici->v4l2_dev, spi_master, + shd->board_info_spi); + if (!subdev) { + ret = -ENODEV; + goto espind; + } + + spi = v4l2_get_subdevdata(subdev); + + icd->control = &spi->dev; + + return 0; +espind: + v4l2_clk_unregister(icd->clk); + icd->clk = NULL; +eclkreg: + kfree(ssdd); + return ret; +} + +static void soc_camera_spi_free(struct soc_camera_device *icd) +{ + struct spi_device *spi = + to_spi_device(to_soc_camera_control(icd)); + struct soc_camera_subdev_desc *ssdd; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + + icd->control = NULL; + if (icd->sasc) + return; + ssdd = spi->dev.platform_data; + v4l2_device_unregister_subdev(sd); + spi_unregister_device(spi); + kfree(ssdd); + v4l2_clk_unregister(icd->clk); + icd->clk = NULL; +} + /* * V4L2 asynchronous notifier callbacks. They are all called under a v4l2-async * internal global mutex, therefore cannot race against other asynchronous @@ -1762,6 +1848,10 @@ static int soc_camera_probe(struct soc_camera_host *ici, ret = soc_camera_i2c_init(icd, sdesc); if (ret < 0 && ret != -EPROBE_DEFER) goto eadd; + } else if (shd->board_info_spi) { + ret = soc_camera_spi_init(icd, sdesc); + if (ret < 0) + goto eadd; } else if (!shd->add_device || !shd->del_device) { ret = -EINVAL; goto eadd; @@ -1803,6 +1893,8 @@ static int soc_camera_probe(struct soc_camera_host *ici, efinish: if (shd->board_info) { soc_camera_i2c_free(icd); + } else if (shd->board_info_spi) { + soc_camera_spi_free(icd); } else { shd->del_device(icd); module_put(control->driver->owner); @@ -1843,6 +1935,8 @@ static int soc_camera_remove(struct soc_camera_device *icd) if (sdesc->host_desc.board_info) { soc_camera_i2c_free(icd); + } else if (sdesc->host_desc.board_info_spi) { + soc_camera_spi_free(icd); } else { struct device *dev = to_soc_camera_control(icd); struct device_driver *drv = dev ? dev->driver : NULL; diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 2f6261f..a948ff6 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -178,6 +178,8 @@ struct soc_camera_host_desc { int i2c_adapter_id; struct i2c_board_info *board_info; const char *module_name; + struct spi_board_info *board_info_spi; + int spi_bus_id; /* * For non-I2C devices platform has to provide methods to add a device @@ -243,6 +245,8 @@ struct soc_camera_link { int i2c_adapter_id; struct i2c_board_info *board_info; const char *module_name; + struct spi_board_info *board_info_spi; + int spi_bus_id; /* * For non-I2C devices platform has to provide methods to add a device