diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 70c7d9a3f715f..be73974ce449a 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -543,6 +543,30 @@ static struct device *acpi_lpss_find_device(const char *hid, const char *uid) return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid); } +static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) +{ + struct acpi_handle_list dep_devices; + acpi_status status; + int i; + + if (!acpi_has_method(adev->handle, "_DEP")) + return false; + + status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, + &dep_devices); + if (ACPI_FAILURE(status)) { + dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); + return false; + } + + for (i = 0; i < dep_devices.count; i++) { + if (dep_devices.handles[i] == handle) + return true; + } + + return false; +} + static void acpi_lpss_link_consumer(struct device *dev1, const struct lpss_device_links *link) { diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 13565629ce0a8..a258db713bd25 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1627,7 +1627,7 @@ static int acpi_ec_add(struct acpi_device *device) WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); /* Reprobe devices depending on the EC */ - acpi_walk_dep_device_list(ec->handle); + acpi_dev_flag_dependency_met(ec->handle); acpi_handle_debug(ec->handle, "enumerated.\n"); return 0; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 68fc6a03aed18..e6a5d997241c4 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -79,7 +79,6 @@ static inline void acpi_lpss_init(void) {} #endif void acpi_apd_init(void); -bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle); acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); bool acpi_queue_hotplug_work(struct work_struct *work); diff --git a/drivers/acpi/pmic/Kconfig b/drivers/acpi/pmic/Kconfig index e27d8ef3a32cc..56bbcb2ce61b2 100644 --- a/drivers/acpi/pmic/Kconfig +++ b/drivers/acpi/pmic/Kconfig @@ -52,6 +52,7 @@ endif # PMIC_OPREGION config TPS68470_PMIC_OPREGION bool "ACPI operation region support for TPS68470 PMIC" + depends on MFD_TPS68470 help This config adds ACPI operation region support for TI TPS68470 PMIC. TPS68470 device is an advanced power management unit that powers diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c index a5101b07611aa..59cca504325ea 100644 --- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -117,7 +117,7 @@ static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev) return err; /* Re-enumerate devices depending on PMIC */ - acpi_walk_dep_device_list(ACPI_HANDLE(pdev->dev.parent)); + acpi_dev_flag_dependency_met(ACPI_HANDLE(pdev->dev.parent)); return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 22566b4b3150a..1419304677a9c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -49,12 +49,6 @@ static DEFINE_MUTEX(acpi_hp_context_lock); */ static u64 spcr_uart_addr; -struct acpi_dep_data { - struct list_head node; - acpi_handle supplier; - acpi_handle consumer; -}; - void acpi_scan_lock_acquire(void) { mutex_lock(&acpi_scan_lock); @@ -2114,30 +2108,106 @@ static void acpi_bus_attach(struct acpi_device *device, bool first_pass) device->handler->hotplug.notify_online(device); } -void acpi_walk_dep_device_list(acpi_handle handle) +static int __acpi_dev_get_dependent_dev(struct acpi_dep_data *dep, void *data) +{ + struct acpi_device *adev; + int ret; + + ret = acpi_bus_get_device(dep->consumer, &adev); + if (ret) + /* If we don't find an adev then we want to continue parsing */ + return 0; + + *(struct acpi_device **)data = adev; + + return 1; +} + +static int __acpi_dev_flag_dependency_met(struct acpi_dep_data *dep, + void *data) { - struct acpi_dep_data *dep, *tmp; struct acpi_device *adev; + acpi_bus_get_device(dep->consumer, &adev); + if (!adev) + return 0; + + adev->dep_unmet--; + if (!adev->dep_unmet) + acpi_bus_attach(adev, true); + + list_del(&dep->node); + kfree(dep); + return 0; +} + +/** + * acpi_walk_dep_device_list - Apply a callback to every entry in acpi_dep_list + * @handle: The ACPI handle of the supplier device + * @callback: Pointer to the callback function to apply + * @data: Pointer to some data to pass to the callback + * + * The return value of the callback determines this function's behaviour. If 0 + * is returned we continue to iterate over acpi_dep_list. If a positive value + * is returned then the loop is broken but this function returns 0. If a + * negative value is returned by the callback then the loop is broken and that + * value is returned as the final error. + */ +int acpi_walk_dep_device_list(acpi_handle handle, + int (*callback)(struct acpi_dep_data *, void *), + void *data) +{ + struct acpi_dep_data *dep, *tmp; + int ret; + mutex_lock(&acpi_dep_list_lock); list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) { if (dep->supplier == handle) { - acpi_bus_get_device(dep->consumer, &adev); - - if (adev) { - adev->dep_unmet--; - if (!adev->dep_unmet) - acpi_bus_attach(adev, true); - } - - list_del(&dep->node); - kfree(dep); + ret = callback(dep, data); + if (ret) + break; } } mutex_unlock(&acpi_dep_list_lock); + + return ret > 0 ? 0 : ret; } EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list); +/** + * acpi_dev_flag_dependency_met() - Inform consumers of @handle that the device + * is now active + * @handle: acpi_handle for the supplier device + * + * This function walks through the dependencies list and informs each consumer + * of @handle that their dependency upon it is now met. Devices with no more + * unmet dependencies will be attached to the acpi bus. + */ +void acpi_dev_flag_dependency_met(acpi_handle handle) +{ + acpi_walk_dep_device_list(handle, __acpi_dev_flag_dependency_met, NULL); +} +EXPORT_SYMBOL_GPL(acpi_dev_flag_dependency_met); + +/** + * acpi_dev_get_dependent_dev - Return ACPI device dependent on @supplier + * @supplier: Pointer to the dependee device + * + * Returns the first &struct acpi_device which declares itself dependent on + * @supplier via the _DEP buffer, parsed from the acpi_dep_list. + */ +struct acpi_device * +acpi_dev_get_dependent_dev(struct acpi_device *supplier) +{ + struct acpi_device *adev = NULL; + + acpi_walk_dep_device_list(supplier->handle, + __acpi_dev_get_dependent_dev, &adev); + + return adev; +} +EXPORT_SYMBOL_GPL(acpi_dev_get_dependent_dev); + /** * acpi_bus_scan - Add ACPI device node objects in a given namespace scope. * @handle: Root of the namespace scope to scan. diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index ec6a2406a8866..ddca1550cce6f 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -807,42 +807,6 @@ static int acpi_dev_match_cb(struct device *dev, const void *data) return hrv == match->hrv; } -bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) -{ - struct acpi_handle_list dep_devices; - acpi_status status; - int i; - - if (!acpi_has_method(adev->handle, "_DEP")) - return false; - - status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, - &dep_devices); - if (ACPI_FAILURE(status)) { - dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); - return false; - } - - for (i = 0; i < dep_devices.count; i++) { - if (dep_devices.handles[i] == handle) - return true; - } - - return false; -} - -static int acpi_dev_match_by_dep(struct device *dev, const void *data) -{ - struct acpi_device *adev = to_acpi_device(dev); - const struct acpi_device *dependee = data; - acpi_handle handle = dependee->handle; - - if (acpi_lpss_dep(adev, handle)) - return 1; - - return 0; -} - /** * acpi_dev_present - Detect that a given ACPI device is present * @hid: Hardware ID of the device. @@ -878,28 +842,6 @@ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) } EXPORT_SYMBOL(acpi_dev_present); -/** - * acpi_dev_get_next_dep_dev - Return next ACPI device dependent on input dev - * @adev: Pointer to the dependee device - * @prev: Pointer to the previous dependent device (or NULL for first match) - * - * Return the next ACPI device which declares itself dependent on @adev in - * the _DEP buffer. - * - * The caller is responsible to call put_device() on the returned device. - */ -struct acpi_device *acpi_dev_get_next_dep_dev(struct acpi_device *adev, - struct acpi_device *prev) -{ - struct device *start = prev ? &prev->dev : NULL; - struct device *dev; - - dev = bus_find_device(&acpi_bus_type, start, adev, acpi_dev_match_by_dep); - - return dev ? to_acpi_device(dev) : NULL; -} -EXPORT_SYMBOL(acpi_dev_get_next_dep_dev); - /** * acpi_dev_get_next_match_dev - Return the next match of ACPI device * @adev: Pointer to the previous acpi_device matching this @hid, @uid and @hrv diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 27b43d9c5da6f..fa225175e68de 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1347,6 +1347,7 @@ config GPIO_TPS65912 config GPIO_TPS68470 bool "TPS68470 GPIO" + depends on MFD_TPS68470 help Select this option to enable GPIO driver for the TPS68470 chip family. diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 83f9f85cd0ab7..0cc7cc3277579 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -102,7 +102,8 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) } /** - * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API + * __acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with + * GPIO API * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") * @pin: ACPI GPIO pin number (0-based, controller-relative) * @@ -111,7 +112,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) * controller does not have GPIO chip registered at the moment. This is to * support probe deferral. */ -struct gpio_desc *acpi_get_gpiod(char *path, int pin) +static struct gpio_desc *__acpi_get_gpiod(char *path, int pin) { struct gpio_chip *chip; acpi_handle handle; @@ -127,6 +128,32 @@ struct gpio_desc *acpi_get_gpiod(char *path, int pin) return gpiochip_get_desc(chip, pin); } + +/** + * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with + * GPIO API, and hold a refcount to the GPIO device. + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") + * @pin: ACPI GPIO pin number (0-based, controller-relative) + * @label: Label to pass to gpiod_request() + * + * This function is a simple pass-through to __acpi_get_gpiod(), except that as + * it is intended for use outside of the GPIO layer (in a similar fashion to + * gpiod_get_index() for example) it also holds a reference to the GPIO device. + */ +struct gpio_desc *acpi_get_gpiod(char *path, int pin, char *label) +{ + struct gpio_desc *gpio = __acpi_get_gpiod(path, pin); + int ret; + + if (IS_ERR(gpio)) + return gpio; + + ret = gpiod_request(gpio, label); + if (ret) + return ERR_PTR(ret); + + return gpio; +} EXPORT_SYMBOL_GPL(acpi_get_gpiod); static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) @@ -690,8 +717,8 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) if (pin_index >= agpio->pin_table_length) return 1; - lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, - agpio->pin_table[pin_index]); + lookup->desc = __acpi_get_gpiod(agpio->resource_source.string_ptr, + agpio->pin_table[pin_index]); lookup->info.pin_config = agpio->pin_config; lookup->info.debounce = agpio->debounce_timeout; lookup->info.gpioint = gpioint; @@ -1255,7 +1282,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) acpi_gpiochip_request_regions(acpi_gpio); acpi_gpiochip_scan_gpios(acpi_gpio); - acpi_walk_dep_device_list(handle); + acpi_dev_flag_dependency_met(handle); } void acpi_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 89751415b69b8..9d9b503741ad7 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -283,7 +283,7 @@ void i2c_acpi_register_devices(struct i2c_adapter *adap) if (!handle) return; - acpi_walk_dep_device_list(handle); + acpi_dev_flag_dependency_met(handle); } static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = { @@ -497,22 +497,6 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, } EXPORT_SYMBOL_GPL(i2c_acpi_new_device); -/** - * i2c_acpi_dev_name - Construct i2c device name for devs sourced from ACPI - * @adev: ACPI device to construct the name for - * - * Constructs the name of an i2c device matching the format used by - * i2c_dev_set_name() to allow users to refer to an i2c device by name even - * before they have been instantiated. - * - * The caller is responsible for freeing the returned pointer. - */ -char *i2c_acpi_dev_name(struct acpi_device *adev) -{ - return kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev)); -} -EXPORT_SYMBOL_GPL(i2c_acpi_dev_name); - #ifdef CONFIG_ACPI_I2C_OPREGION static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, u8 cmd, u8 *data, u8 data_len) diff --git a/drivers/media/i2c/ad5823.h b/drivers/media/i2c/ad5823.h deleted file mode 100644 index f1362cd69f6e6..0000000000000 --- a/drivers/media/i2c/ad5823.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for AD5823 VCM. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * 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. - * - * - */ - -#ifndef __AD5823_H__ -#define __AD5823_H__ - -#include - -#define AD5823_VCM_ADDR 0x0c - -#define AD5823_REG_RESET 0x01 -#define AD5823_REG_MODE 0x02 -#define AD5823_REG_VCM_MOVE_TIME 0x03 -#define AD5823_REG_VCM_CODE_MSB 0x04 -#define AD5823_REG_VCM_CODE_LSB 0x05 -#define AD5823_REG_VCM_THRESHOLD_MSB 0x06 -#define AD5823_REG_VCM_THRESHOLD_LSB 0x07 - -#define AD5823_REG_LENGTH 0x1 - -#define AD5823_RING_CTRL_ENABLE 0x04 -#define AD5823_RING_CTRL_DISABLE 0x00 - -#define AD5823_RESONANCE_PERIOD 100000 -#define AD5823_RESONANCE_COEF 512 -#define AD5823_HIGH_FREQ_RANGE 0x80 - -#define VCM_CODE_MSB_MASK 0xfc -#define AD5823_INIT_FOCUS_POS 350 - -enum ad5823_tok_type { - AD5823_8BIT = 0x1, - AD5823_16BIT = 0x2, -}; - -enum ad5823_vcm_mode { - AD5823_ARC_RES0 = 0x0, /* Actuator response control RES1 */ - AD5823_ARC_RES1 = 0x1, /* Actuator response control RES0.5 */ - AD5823_ARC_RES2 = 0x2, /* Actuator response control RES2 */ - AD5823_ESRC = 0x3, /* Enhanced slew rate control */ - AD5823_DIRECT = 0x4, /* Direct control */ -}; - -#define AD5823_INVALID_CONFIG 0xffffffff -#define AD5823_MAX_FOCUS_POS 1023 -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) -#endif diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 09c84006d5c90..4a6b513191450 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1,19 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Support for OmniVision OV5693 1080p HD camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * 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. - * + * Adapted from the atomisp-ov5693 driver, with contributions from: * + * Daniel Scally + * Fabian Wuthrich + * Tsuchiya Yuto + * Jordan Hand + * Jake Day */ #include @@ -25,442 +18,571 @@ #include #include #include +#include #include #include +#include -#include "ov5693.h" -#include "ad5823.h" +/* System Control */ +#define OV5693_SW_RESET_REG 0x0103 +#define OV5693_SW_STREAM_REG 0x0100 +#define OV5693_START_STREAMING 0x01 +#define OV5693_STOP_STREAMING 0x00 +#define OV5693_SW_RESET 0x01 -/* Exposure/gain */ +#define OV5693_REG_CHIP_ID_H 0x300A +#define OV5693_REG_CHIP_ID_L 0x300B +/* Yes, this is right. The datasheet for the OV5693 gives its ID as 0x5690 */ +#define OV5693_CHIP_ID 0x5690 -#define OV5693_EXPOSURE_CTRL_HH_REG 0x3500 +/* Exposure */ +#define OV5693_EXPOSURE_L_CTRL_HH_REG 0x3500 +#define OV5693_EXPOSURE_L_CTRL_H_REG 0x3501 +#define OV5693_EXPOSURE_L_CTRL_L_REG 0x3502 +#define OV5693_EXPOSURE_S_CTRL_HH_REG 0x3506 +#define OV5693_EXPOSURE_S_CTRL_H_REG 0x3507 +#define OV5693_EXPOSURE_S_CTRL_L_REG 0x3508 #define OV5693_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(14, 12)) >> 12) -#define OV5693_EXPOSURE_CTRL_H_REG 0x3501 #define OV5693_EXPOSURE_CTRL_H(v) (((v) & GENMASK(11, 4)) >> 4) -#define OV5693_EXPOSURE_CTRL_L_REG 0x3502 #define OV5693_EXPOSURE_CTRL_L(v) (((v) & GENMASK(3, 0)) << 4) -#define OV5693_EXPOSURE_GAIN_MANUAL_REG 0x3509 - -#define OV5693_GAIN_CTRL_H_REG 0x3504 -#define OV5693_GAIN_CTRL_H(v) ((v >> 4) & GENMASK(2, 0)) -#define OV5693_GAIN_CTRL_L_REG 0x3505 -#define OV5693_GAIN_CTRL_L(v) ((v << 4) & GENMASK(7, 4)) +#define OV5693_INTEGRATION_TIME_MARGIN 8 +#define OV5693_EXPOSURE_MIN 1 +#define OV5693_EXPOSURE_STEP 1 + +/* Analogue Gain */ +#define OV5693_GAIN_CTRL_H_REG 0x350A +#define OV5693_GAIN_CTRL_H(v) (((v) >> 4) & GENMASK(2, 0)) +#define OV5693_GAIN_CTRL_L_REG 0x350B +#define OV5693_GAIN_CTRL_L(v) (((v) << 4) & GENMASK(7, 4)) +#define OV5693_GAIN_MIN 1 +#define OV5693_GAIN_MAX 127 +#define OV5693_GAIN_DEF 8 +#define OV5693_GAIN_STEP 1 + +/* Digital Gain */ +#define OV5693_MWB_RED_GAIN_H_REG 0x3400 +#define OV5693_MWB_RED_GAIN_L_REG 0x3401 +#define OV5693_MWB_GREEN_GAIN_H_REG 0x3402 +#define OV5693_MWB_GREEN_GAIN_L_REG 0x3403 +#define OV5693_MWB_BLUE_GAIN_H_REG 0x3404 +#define OV5693_MWB_BLUE_GAIN_L_REG 0x3405 +#define OV5693_MWB_GAIN_H_CTRL(v) (((v) >> 8) & GENMASK(3, 0)) +#define OV5693_MWB_GAIN_L_CTRL(v) ((v) & GENMASK(7, 0)) +#define OV5693_MWB_GAIN_MAX 0x0fff +#define OV5693_DIGITAL_GAIN_MIN 1 +#define OV5693_DIGITAL_GAIN_MAX 4095 +#define OV5693_DIGITAL_GAIN_DEF 1024 +#define OV5693_DIGITAL_GAIN_STEP 1 + +/* Timing and Format */ +#define OV5693_CROP_START_X_H_REG 0x3800 +#define OV5693_CROP_START_X_L_REG 0x3801 +#define OV5693_CROP_START_X_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_CROP_START_Y_H_REG 0x3802 +#define OV5693_CROP_START_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) +#define OV5693_CROP_START_Y_L_REG 0x3803 +#define OV5693_CROP_START_Y_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_CROP_END_X_H_REG 0x3804 +#define OV5693_CROP_END_X_H(v) (((v) & GENMASK(12, 8)) >> 8) +#define OV5693_CROP_END_X_L_REG 0x3805 +#define OV5693_CROP_END_X_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_CROP_END_Y_H_REG 0x3806 +#define OV5693_CROP_END_Y_H(v) (((v) & GENMASK(11, 8)) >> 8) +#define OV5693_CROP_END_Y_L_REG 0x3807 +#define OV5693_CROP_END_Y_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_OUTPUT_SIZE_X_H_REG 0x3808 +#define OV5693_OUTPUT_SIZE_X_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_OUTPUT_SIZE_X_L_REG 0x3809 +#define OV5693_OUTPUT_SIZE_X_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_OUTPUT_SIZE_Y_H_REG 0x380a +#define OV5693_OUTPUT_SIZE_Y_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_OUTPUT_SIZE_Y_L_REG 0x380b +#define OV5693_OUTPUT_SIZE_Y_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_TIMING_HTS_H_REG 0x380c +#define OV5693_TIMING_HTS_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_TIMING_HTS_L_REG 0x380d +#define OV5693_TIMING_HTS_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_TIMING_VTS_H_REG 0x380e +#define OV5693_TIMING_VTS_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_TIMING_VTS_L_REG 0x380f +#define OV5693_TIMING_VTS_L(v) ((v) & GENMASK(7, 0)) +#define OV5693_TIMING_MAX_VTS 0xffff +#define OV5693_TIMING_MIN_VTS 0x04 + +#define OV5693_OFFSET_START_X_H_REG 0x3810 +#define OV5693_OFFSET_START_X_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_OFFSET_START_X_L_REG 0x3811 +#define OV5693_OFFSET_START_X_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_OFFSET_START_Y_H_REG 0x3812 +#define OV5693_OFFSET_START_Y_H(v) (((v) & GENMASK(15, 8)) >> 8) +#define OV5693_OFFSET_START_Y_L_REG 0x3813 +#define OV5693_OFFSET_START_Y_L(v) ((v) & GENMASK(7, 0)) + +#define OV5693_SUB_INC_X_REG 0x3814 +#define OV5693_SUB_INC_Y_REG 0x3815 #define OV5693_FORMAT1_REG 0x3820 #define OV5693_FORMAT1_FLIP_VERT_ISP_EN BIT(2) #define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1) +#define OV5693_FORMAT1_VBIN_EN BIT(0) #define OV5693_FORMAT2_REG 0x3821 -#define OV5693_FORMAT2_HSYNC_EN BIT(6) -#define OV5693_FORMAT2_FST_VBIN_EN BIT(5) -#define OV5693_FORMAT2_FST_HBIN_EN BIT(4) -#define OV5693_FORMAT2_ISP_HORZ_VAR2_EN BIT(3) +#define OV5693_FORMAT2_HDR_EN BIT(7) #define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2) #define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1) -#define OV5693_FORMAT2_SYNC_HBIN_EN BIT(0) - -/* ISP */ - -#define OV5693_ISP_CTRL0_REG 0x5000 -#define OV5693_ISP_CTRL0_LENC_EN BIT(7) -#define OV5693_ISP_CTRL0_WHITE_BALANCE_EN BIT(4) -#define OV5693_ISP_CTRL0_DPC_BLACK_EN BIT(2) -#define OV5693_ISP_CTRL0_DPC_WHITE_EN BIT(1) -#define OV5693_ISP_CTRL1_REG 0x5001 -#define OV5693_ISP_CTRL1_BLC_EN BIT(0) - -/* native and active pixel array size. */ -#define OV5693_NATIVE_WIDTH 2688U -#define OV5693_NATIVE_HEIGHT 1984U -#define OV5693_PIXEL_ARRAY_LEFT 48U -#define OV5693_PIXEL_ARRAY_TOP 20U -#define OV5693_PIXEL_ARRAY_WIDTH 2592U -#define OV5693_PIXEL_ARRAY_HEIGHT 1944U - -/* i2c read/write stuff */ -static int ov5693_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT - && data_length != OV5693_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } +#define OV5693_FORMAT2_HBIN_EN BIT(0) + +#define OV5693_ISP_CTRL2_REG 0x5002 +#define OV5693_ISP_SCALE_ENABLE BIT(7) + +/* Pixel Array */ +#define OV5693_NATIVE_WIDTH 2624U +#define OV5693_NATIVE_HEIGHT 1956U +#define OV5693_ACTIVE_START_LEFT 16U +#define OV5693_ACTIVE_START_TOP 6U +#define OV5693_ACTIVE_WIDTH 2592U +#define OV5693_ACTIVE_HEIGHT 1944U + +/* Test Pattern */ +#define OV5693_TEST_PATTERN_REG 0x5e00 +#define OV5693_TEST_PATTERN_ENABLE BIT(7) +#define OV5693_TEST_PATTERN_ROLLING BIT(6) +#define OV5693_TEST_PATTERN_RANDOM 0x01 +#define OV5693_TEST_PATTERN_BARS 0x00 + +/* System Frequencies */ +#define OV5693_XVCLK_FREQ 19200000 +#define OV5693_LINK_FREQ_400MHZ 400000000 +#define OV5693_PIXEL_RATE 160000000 + +/* Miscellaneous */ +#define OV5693_NUM_MBUS_FMTS 1 +#define OV5693_NUM_SUPPLIES 2 + +#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd) + +struct ov5693_reg { + u16 reg; + u8 val; +}; - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } +struct ov5693_reg_list { + u32 num_regs; + const struct ov5693_reg *regs; +}; - *val = 0; - /* high byte comes first */ - if (data_length == OV5693_8BIT) - *val = (u8)data[0]; - else if (data_length == OV5693_16BIT) - *val = be16_to_cpu(*(__be16 *)&data[0]); - else - *val = be32_to_cpu(*(__be32 *)&data[0]); +struct ov5693_resolution { + char *desc; + int fps; - return 0; -} + struct v4l2_rect crop; -static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; + unsigned int crop_start_x; + unsigned int offset_x; + unsigned int output_size_x; + unsigned int crop_end_x; + unsigned int hts; - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); + unsigned int crop_start_y; + unsigned int offset_y; + unsigned int output_size_y; + unsigned int crop_end_y; + unsigned int vts; - return ret == num_msg ? 0 : -EIO; -} + unsigned int inc_x_odd; + unsigned int inc_x_even; + unsigned int inc_y_odd; + unsigned int inc_y_even; -static int ov5693_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - __be16 *wreg = (void *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + bool binning_x; + bool binning_y; + bool scale_enable; +}; - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } +struct ov5693_device { + struct i2c_client *client; + struct device *dev; - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); + /* Protect against concurrent changes to controls */ + struct mutex lock; - if (data_length == OV5693_8BIT) { - data[2] = (u8)(val); - } else { - /* OV5693_16BIT */ - __be16 *wdata = (void *)&data[2]; + struct gpio_desc *reset; + struct gpio_desc *powerdown; + struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; + struct clk *clk; - *wdata = cpu_to_be16(val); - } + const struct ov5693_resolution *mode; + bool streaming; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct ov5693_v4l2_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *analogue_gain; + struct v4l2_ctrl *digital_gain; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + } ctrls; +}; - ret = ov5693_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); +static const struct ov5693_reg ov5693_global_regs[] = { + {0x0103, 0x01}, + {0x3016, 0xf0}, + {0x3017, 0xf0}, + {0x3018, 0xf0}, + {0x3022, 0x01}, + {0x3028, 0x44}, + {0x3098, 0x02}, + {0x3099, 0x19}, + {0x309a, 0x02}, + {0x309b, 0x01}, + {0x309c, 0x00}, + {0x30a0, 0xd2}, + {0x30a2, 0x01}, + {0x30b2, 0x00}, + {0x30b3, 0x7d}, + {0x30b4, 0x03}, + {0x30b5, 0x04}, + {0x30b6, 0x01}, + {0x3104, 0x21}, + {0x3106, 0x00}, + {0x3406, 0x01}, + {0x3503, 0x07}, + {0x350b, 0x40}, + {0x3601, 0x0a}, + {0x3602, 0x38}, + {0x3612, 0x80}, + {0x3620, 0x54}, + {0x3621, 0xc7}, + {0x3622, 0x0f}, + {0x3625, 0x10}, + {0x3630, 0x55}, + {0x3631, 0xf4}, + {0x3632, 0x00}, + {0x3633, 0x34}, + {0x3634, 0x02}, + {0x364d, 0x0d}, + {0x364f, 0xdd}, + {0x3660, 0x04}, + {0x3662, 0x10}, + {0x3663, 0xf1}, + {0x3665, 0x00}, + {0x3666, 0x20}, + {0x3667, 0x00}, + {0x366a, 0x80}, + {0x3680, 0xe0}, + {0x3681, 0x00}, + {0x3700, 0x42}, + {0x3701, 0x14}, + {0x3702, 0xa0}, + {0x3703, 0xd8}, + {0x3704, 0x78}, + {0x3705, 0x02}, + {0x370a, 0x00}, + {0x370b, 0x20}, + {0x370c, 0x0c}, + {0x370d, 0x11}, + {0x370e, 0x00}, + {0x370f, 0x40}, + {0x3710, 0x00}, + {0x371a, 0x1c}, + {0x371b, 0x05}, + {0x371c, 0x01}, + {0x371e, 0xa1}, + {0x371f, 0x0c}, + {0x3721, 0x00}, + {0x3724, 0x10}, + {0x3726, 0x00}, + {0x372a, 0x01}, + {0x3730, 0x10}, + {0x3738, 0x22}, + {0x3739, 0xe5}, + {0x373a, 0x50}, + {0x373b, 0x02}, + {0x373c, 0x41}, + {0x373f, 0x02}, + {0x3740, 0x42}, + {0x3741, 0x02}, + {0x3742, 0x18}, + {0x3743, 0x01}, + {0x3744, 0x02}, + {0x3747, 0x10}, + {0x374c, 0x04}, + {0x3751, 0xf0}, + {0x3752, 0x00}, + {0x3753, 0x00}, + {0x3754, 0xc0}, + {0x3755, 0x00}, + {0x3756, 0x1a}, + {0x3758, 0x00}, + {0x3759, 0x0f}, + {0x376b, 0x44}, + {0x375c, 0x04}, + {0x3774, 0x10}, + {0x3776, 0x00}, + {0x377f, 0x08}, + {0x3780, 0x22}, + {0x3781, 0x0c}, + {0x3784, 0x2c}, + {0x3785, 0x1e}, + {0x378f, 0xf5}, + {0x3791, 0xb0}, + {0x3795, 0x00}, + {0x3796, 0x64}, + {0x3797, 0x11}, + {0x3798, 0x30}, + {0x3799, 0x41}, + {0x379a, 0x07}, + {0x379b, 0xb0}, + {0x379c, 0x0c}, + {0x3a04, 0x06}, + {0x3a05, 0x14}, + {0x3e07, 0x20}, + {0x4000, 0x08}, + {0x4001, 0x04}, + {0x4004, 0x08}, + {0x4006, 0x20}, + {0x4008, 0x24}, + {0x4009, 0x10}, + {0x4058, 0x00}, + {0x4101, 0xb2}, + {0x4307, 0x31}, + {0x4511, 0x05}, + {0x4512, 0x01}, + {0x481f, 0x30}, + {0x4826, 0x2c}, + {0x4d02, 0xfd}, + {0x4d03, 0xf5}, + {0x4d04, 0x0c}, + {0x4d05, 0xcc}, + {0x4837, 0x0a}, + {0x5003, 0x20}, + {0x5013, 0x00}, + {0x5842, 0x01}, + {0x5843, 0x2b}, + {0x5844, 0x01}, + {0x5845, 0x92}, + {0x5846, 0x01}, + {0x5847, 0x8f}, + {0x5848, 0x01}, + {0x5849, 0x0c}, + {0x5e10, 0x0c}, + {0x3820, 0x00}, + {0x3821, 0x1e}, + {0x5041, 0x14} +}; - return ret; -} +static const struct ov5693_reg_list ov5693_global_setting = { + .num_regs = ARRAY_SIZE(ov5693_global_regs), + .regs = ov5693_global_regs, +}; -/* - * ov5693_write_reg_array - Initializes a list of OV5693 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and - * __ov5693_write_reg_is_consecutive() are internal functions to - * ov5693_write_reg_array_fast() and should be not used anywhere else. - * - */ +#define OV5693_NUM_RESOLUTIONS ARRAY_SIZE(ov5693_resolutions) +struct ov5693_resolution ov5693_resolutions[] = { + { + .desc = "ov5693_2592x1944_30fps", + .fps = 30, + + .crop_start_x = 16, + .offset_x = 0, + .output_size_x = 2592, + .crop_end_x = 2608, + .hts = 2688, + + .crop_start_y = 6, + .offset_y = 0, + .output_size_y = 1944, + .crop_end_y = 1950, + .vts = 1984, + + .inc_x_odd = 1, + .inc_x_even = 1, + .inc_y_odd = 1, + .inc_y_even = 1, + + .crop = { + .left = 16, + .top = 6, + .width = 2592, + .height = 1944 + }, + }, + { + .desc = "ov5693_1920x1080_30fps", + .fps = 30, + + .crop_start_x = 16, + .offset_x = 0, + .output_size_x = 1920, + .crop_end_x = 2608, + .hts = 2688, + + .crop_start_y = 249, + .offset_y = 0, + .output_size_y = 1080, + .crop_end_y = 1707, + .vts = 1984, + + .scale_enable = true, + + .inc_x_odd = 1, + .inc_x_even = 1, + .inc_y_odd = 1, + .inc_y_even = 1, + + .crop = { + .left = 352, + .top = 438, + .width = 1920, + .height = 1080 + }, + }, + { + .desc = "ov5693_1280x720_60fps", + .fps = 60, + + .crop_start_x = 32, + .offset_x = 0, + .output_size_x = 1280, + .crop_end_x = 2592, + .binning_x = true, + .hts = 2688, + + .crop_start_y = 252, + .offset_y = 0, + .output_size_y = 720, + .crop_end_y = 1692, + .binning_y = true, + .vts = 992, + + .inc_x_odd = 3, + .inc_x_even = 1, + .inc_y_odd = 3, + .inc_y_even = 1, + + .crop = { + .left = 0, + .top = 0, + .width = 1280, + .height = 720 + }, + } +}; -static int __ov5693_flush_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl) -{ - u16 size; - __be16 *reg = (void *)&ctrl->buffer.addr; +static const s64 link_freq_menu_items[] = { + OV5693_LINK_FREQ_400MHZ +}; - if (ctrl->index == 0) - return 0; +static const char * const ov5693_supply_names[] = { + "avdd", + "dovdd", +}; - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ +static const char * const ov5693_test_pattern_menu[] = { + "Disabled", + "Random Data", + "Colour Bars", + "Colour Bars with Rolling Bar" +}; - *reg = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; +static const u8 ov5693_test_pattern_bits[] = { + 0, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_RANDOM, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_BARS, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_BARS | + OV5693_TEST_PATTERN_ROLLING, +}; - return ov5693_i2c_write(client, size, (u8 *)reg); -} +/* I2C I/O Operations */ -static int __ov5693_buf_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) +static int ov5693_read_reg(struct ov5693_device *ov5693, u16 addr, u8 *value) { - int size; - __be16 *data16; - - switch (next->type) { - case OV5693_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV5693_16BIT: - size = 2; + unsigned char data[2] = { addr >> 8, addr & 0xff }; + struct i2c_client *client = ov5693->client; + int ret; - data16 = (void *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; + ret = i2c_master_send(client, data, sizeof(data)); + if (ret < 0) { + dev_dbg(&client->dev, "i2c send error at address 0x%04x\n", + addr); + return ret; } - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) - return __ov5693_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov5693_write_reg_array(struct i2c_client *client, - const struct ov5693_reg *reglist) -{ - const struct ov5693_reg *next = reglist; - struct ov5693_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV5693_TOK_TERM; next++) { - switch (next->type & OV5693_TOK_MASK) { - case OV5693_TOK_DELAY: - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov5693_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov5693_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, - "%s: write error, aborted\n", - __func__); - return err; - } - break; - } + ret = i2c_master_recv(client, value, 1); + if (ret < 0) { + dev_dbg(&client->dev, "i2c recv error at address 0x%04x\n", + addr); + return ret; } - return __ov5693_flush_reg_array(client, &ctrl); + return 0; } -static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, - u16 addr, u8 *buf) +static void ov5693_write_reg(struct ov5693_device *ov5693, u16 addr, u8 value, + int *error) { - u16 index; + unsigned char data[3] = { addr >> 8, addr & 0xff, value }; int ret; - u16 *pVal = NULL; - for (index = 0; index <= size; index++) { - pVal = (u16 *)(buf + index); - ret = - ov5693_read_reg(client, OV5693_8BIT, addr + index, - pVal); - if (ret) - return ret; - } - - return 0; -} + if (*error < 0) + return; -static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *ov5693 = to_ov5693_sensor(sd); - int ret; - int i; - u8 *b = buf; - - ov5693->otp_size = 0; - for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { - /*set bank NO and OTP read mode. */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, - (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no - if (ret) { - dev_err(&client->dev, "failed to prepare OTP page\n"); - return ret; - } - //dev_dbg(&client->dev, "write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); - - /*enable read */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, - OV5693_OTP_MODE_READ); // enable :1 - if (ret) { - dev_err(&client->dev, - "failed to set OTP reading mode page"); - return ret; - } - //dev_dbg(&client->dev, "write 0x%x->0x%x\n", - // OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); - - /* Reading the OTP data array */ - ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, - OV5693_OTP_START_ADDR, - b); - if (ret) { - dev_err(&client->dev, "failed to read OTP data\n"); - return ret; - } - - //dev_dbg(&client->dev, - // "BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - // i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), - // *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); - - //Intel OTP map, try to read 320byts first. - if (i == 21) { - if ((*b) == 0) { - ov5693->otp_size = 320; - break; - } - /* (*b) != 0 */ - b = buf; - continue; - } else if (i == - 24) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. - if ((*b) == 0) { - ov5693->otp_size = 32; - break; - } - /* (*b) != 0 */ - b = buf; - continue; - } else if (i == - 27) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. - if ((*b) == 0) { - ov5693->otp_size = 32; - break; - } - /* (*b) != 0 */ - ov5693->otp_size = 0; // no OTP data. - break; - } - - b = b + OV5693_OTP_BANK_SIZE; + ret = i2c_master_send(ov5693->client, data, sizeof(data)); + if (ret < 0) { + dev_dbg(ov5693->dev, "i2c send error at address 0x%04x: %d\n", + addr, ret); + *error = ret; } - return 0; } -/* - * Read otp data and store it into a kmalloced buffer. - * The caller must kfree the buffer when no more needed. - * @size: set to the size of the returned otp data. - */ -static void *ov5693_otp_read(struct v4l2_subdev *sd) +static int ov5693_write_reg_array(struct ov5693_device *ov5693, + const struct ov5693_reg_list *reglist) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - - buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - //otp valid after mipi on and sw stream on - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_START_STREAMING); - - ret = __ov5693_otp_read(sd, buf); - - //mipi off and sw stream off after otp read - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); + unsigned int i; + int ret = 0; - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_STOP_STREAMING); + for (i = 0; i < reglist->num_regs; i++) + ov5693_write_reg(ov5693, reglist->regs[i].reg, + reglist->regs[i].val, &ret); - /* Driver has failed to find valid data */ - if (ret) { - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); - } - - return buf; + return ret; } static int ov5693_update_bits(struct ov5693_device *ov5693, u16 address, u16 mask, u16 bits) { - u16 value = 0; + u8 value = 0; int ret; - ret = ov5693_read_reg(ov5693->client, OV5693_8BIT, address, &value); + ret = ov5693_read_reg(ov5693, address, &value); if (ret) return ret; value &= ~mask; value |= bits; - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, address, value); + ov5693_write_reg(ov5693, address, value, &ret); if (ret) return ret; return 0; } -/* Flip */ +/* V4L2 Controls Functions */ static int ov5693_flip_vert_configure(struct ov5693_device *ov5693, bool enable) { @@ -490,192 +612,165 @@ static int ov5693_flip_horz_configure(struct ov5693_device *ov5693, bool enable) return 0; } -/* - * This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) +static int ov5693_get_exposure(struct ov5693_device *ov5693, s32 *value) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; + u8 exposure_hh = 0, exposure_h = 0, exposure_l = 0; int ret; - /* get exposure */ - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, - ®_v); + ret = ov5693_read_reg(ov5693, OV5693_EXPOSURE_L_CTRL_HH_REG, &exposure_hh); if (ret) - goto err; + return ret; - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, - ®_v2); + ret = ov5693_read_reg(ov5693, OV5693_EXPOSURE_L_CTRL_H_REG, &exposure_h); if (ret) - goto err; + return ret; - reg_v += reg_v2 << 8; - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, - ®_v2); + ret = ov5693_read_reg(ov5693, OV5693_EXPOSURE_L_CTRL_L_REG, &exposure_l); if (ret) - goto err; + return ret; - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; + *value = ((exposure_hh << 16) | (exposure_h << 8) | exposure_l) >> 4; + + return 0; } -/* Exposure */ static int ov5693_exposure_configure(struct ov5693_device *ov5693, u32 exposure) { - int ret; - - /* - * The control for exposure seems to be in units of lines, but the chip - * datasheet specifies exposure is in units of 1/16th of a line. - */ - exposure = exposure * 16; + int ret = 0; - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, - OV5693_EXPOSURE_CTRL_HH_REG, OV5693_EXPOSURE_CTRL_HH(exposure)); - if (ret) - return ret; + /* Enable HDR Mode to access "short" exposure */ - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, - OV5693_EXPOSURE_CTRL_H_REG, OV5693_EXPOSURE_CTRL_H(exposure)); + ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, + OV5693_FORMAT2_HDR_EN, OV5693_FORMAT2_HDR_EN); if (ret) return ret; - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, - OV5693_EXPOSURE_CTRL_L_REG, OV5693_EXPOSURE_CTRL_L(exposure)); - if (ret) - return ret; + ov5693_write_reg(ov5693, OV5693_EXPOSURE_L_CTRL_HH_REG, + OV5693_EXPOSURE_CTRL_HH(exposure), &ret); + ov5693_write_reg(ov5693, OV5693_EXPOSURE_L_CTRL_H_REG, + OV5693_EXPOSURE_CTRL_H(exposure), &ret); + ov5693_write_reg(ov5693, OV5693_EXPOSURE_L_CTRL_L_REG, + OV5693_EXPOSURE_CTRL_L(exposure), &ret); + ov5693_write_reg(ov5693, OV5693_EXPOSURE_S_CTRL_HH_REG, + OV5693_EXPOSURE_CTRL_HH(exposure), &ret); + ov5693_write_reg(ov5693, OV5693_EXPOSURE_S_CTRL_H_REG, + OV5693_EXPOSURE_CTRL_H(exposure), &ret); + ov5693_write_reg(ov5693, OV5693_EXPOSURE_S_CTRL_L_REG, + OV5693_EXPOSURE_CTRL_L(exposure), &ret); - return 0; + return ret; } -/* Gain */ - static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain) { - u16 gain_l, gain_h; - int ret = 0; + u8 gain_l = 0, gain_h = 0; + int ret; - ret = ov5693_read_reg(ov5693->client, OV5693_8BIT, - OV5693_GAIN_CTRL_L_REG, - &gain_l); + ret = ov5693_read_reg(ov5693, OV5693_GAIN_CTRL_H_REG, &gain_h); if (ret) return ret; - ret = ov5693_read_reg(ov5693->client, OV5693_8BIT, - OV5693_GAIN_CTRL_H_REG, - &gain_h); + ret = ov5693_read_reg(ov5693, OV5693_GAIN_CTRL_L_REG, &gain_l); if (ret) return ret; - *gain = (u32)(((gain_h >> 8) & 0x03) | - (gain_l & 0xff)); + *gain = ((gain_h << 8) | gain_l) >> 4; return ret; } -static int ov5693_gain_configure(struct ov5693_device *ov5693, u32 gain) -{ - int ret; - /* A 1.0 gain is 0x400 */ - gain = (gain * 1024)/1000; +static int ov5693_digital_gain_configure(struct ov5693_device *ov5693, u32 gain) +{ + int ret = 0; - ret = ov5693_write_reg(ov5693->client, OV5693_16BIT, - OV5693_MWB_RED_GAIN_H, gain); - if (ret) { - dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } + ov5693_write_reg(ov5693, OV5693_MWB_RED_GAIN_H_REG, + OV5693_MWB_GAIN_H_CTRL(gain), &ret); + ov5693_write_reg(ov5693, OV5693_MWB_RED_GAIN_L_REG, + OV5693_MWB_GAIN_L_CTRL(gain), &ret); + ov5693_write_reg(ov5693, OV5693_MWB_GREEN_GAIN_H_REG, + OV5693_MWB_GAIN_H_CTRL(gain), &ret); + ov5693_write_reg(ov5693, OV5693_MWB_GREEN_GAIN_L_REG, + OV5693_MWB_GAIN_L_CTRL(gain), &ret); + ov5693_write_reg(ov5693, OV5693_MWB_BLUE_GAIN_H_REG, + OV5693_MWB_GAIN_H_CTRL(gain), &ret); + ov5693_write_reg(ov5693, OV5693_MWB_BLUE_GAIN_L_REG, + OV5693_MWB_GAIN_L_CTRL(gain), &ret); - ret = ov5693_write_reg(ov5693->client, OV5693_16BIT, - OV5693_MWB_GREEN_GAIN_H, gain); - if (ret) { - dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(ov5693->client, OV5693_16BIT, - OV5693_MWB_BLUE_GAIN_H, gain); - if (ret) { - dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - return 0; + return ret; } static int ov5693_analog_gain_configure(struct ov5693_device *ov5693, u32 gain) { - int ret; + int ret = 0; /* * As with exposure, the lowest 4 bits are fractional bits. Setting * those is not supported, so we have a tiny bit of bit shifting to * do. */ - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, - OV5693_AGC_L, OV5693_GAIN_CTRL_L(gain)); - if (ret) { - dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_L); - return ret; - } + ov5693_write_reg(ov5693, OV5693_GAIN_CTRL_L_REG, + OV5693_GAIN_CTRL_L(gain), &ret); + ov5693_write_reg(ov5693, OV5693_GAIN_CTRL_H_REG, + OV5693_GAIN_CTRL_H(gain), &ret); - ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, - OV5693_AGC_H, OV5693_GAIN_CTRL_H(gain)); - if (ret) { - dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_H); - return ret; - } + return ret; +} - return 0; +static int ov5693_vts_configure(struct ov5693_device *ov5693, u32 vblank) +{ + u16 vts = ov5693->mode->output_size_y + vblank; + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_TIMING_VTS_H_REG, + OV5693_TIMING_VTS_H(vts), &ret); + ov5693_write_reg(ov5693, OV5693_TIMING_VTS_L_REG, + OV5693_TIMING_VTS_L(vts), &ret); + + return ret; +} + +static int ov5693_test_pattern_configure(struct ov5693_device *ov5693, u32 idx) +{ + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_TEST_PATTERN_REG, + ov5693_test_pattern_bits[idx], &ret); + + return ret; } static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov5693_device *ov5693 = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd); + container_of(ctrl->handler, struct ov5693_device, ctrls.handler); int ret = 0; /* If VBLANK is altered we need to update exposure to compensate */ if (ctrl->id == V4L2_CID_VBLANK) { int exposure_max; - exposure_max = ov5693->mode->lines_per_frame - 8; - __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, ov5693->ctrls.exposure->minimum, + + exposure_max = ov5693->mode->output_size_y + ctrl->val - + OV5693_INTEGRATION_TIME_MARGIN; + __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, + ov5693->ctrls.exposure->minimum, exposure_max, ov5693->ctrls.exposure->step, ov5693->ctrls.exposure->val < exposure_max ? ov5693->ctrls.exposure->val : exposure_max); } /* Only apply changes to the controls if the device is powered up */ - if (!pm_runtime_get_if_in_use(&ov5693->client->dev)) + if (!pm_runtime_get_if_in_use(ov5693->dev)) return 0; switch (ctrl->id) { case V4L2_CID_EXPOSURE: - dev_dbg(&client->dev, "%s: CID_EXPOSURE:%d.\n", - __func__, ctrl->val); ret = ov5693_exposure_configure(ov5693, ctrl->val); break; case V4L2_CID_ANALOGUE_GAIN: - dev_dbg(&client->dev, "%s: CID_ANALOGUE_GAIN:%d.\n", - __func__, ctrl->val); ret = ov5693_analog_gain_configure(ov5693, ctrl->val); break; case V4L2_CID_DIGITAL_GAIN: - dev_dbg(&client->dev, "%s: CID_DIGITAL_GAIN:%d.\n", - __func__, ctrl->val); - ret = ov5693_gain_configure(ov5693, ctrl->val); + ret = ov5693_digital_gain_configure(ov5693, ctrl->val); break; case V4L2_CID_HFLIP: ret = ov5693_flip_horz_configure(ov5693, !!ctrl->val); @@ -684,14 +779,16 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) ret = ov5693_flip_vert_configure(ov5693, !!ctrl->val); break; case V4L2_CID_VBLANK: - ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_TIMING_VTS_H, - ov5693->mode->height + ctrl->val); + ret = ov5693_vts_configure(ov5693, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov5693_test_pattern_configure(ov5693, ctrl->val); break; default: ret = -EINVAL; } - pm_runtime_put(&ov5693->client->dev); + pm_runtime_put(ov5693->dev); return ret; } @@ -699,24 +796,16 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct ov5693_device *ov5693 = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - int ret = 0; + container_of(ctrl->handler, struct ov5693_device, ctrls.handler); switch (ctrl->id) { case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov5693_q_exposure(&ov5693->sd, &ctrl->val); - break; + return ov5693_get_exposure(ov5693, &ctrl->val); case V4L2_CID_AUTOGAIN: - ret = ov5693_get_gain(ov5693, &ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - /* NOTE: there was atomisp-specific function ov5693_q_focus_abs() */ - break; + return ov5693_get_gain(ov5693, &ctrl->val); default: - ret = -EINVAL; + return -EINVAL; } - - return ret; } static const struct v4l2_ctrl_ops ov5693_ctrl_ops = { @@ -724,44 +813,153 @@ static const struct v4l2_ctrl_ops ov5693_ctrl_ops = { .g_volatile_ctrl = ov5693_g_volatile_ctrl }; +/* System Control Functions */ + +static int ov5693_mode_configure(struct ov5693_device *ov5693) +{ + const struct ov5693_resolution *mode = ov5693->mode; + int ret = 0; + + /* Crop Start X */ + ov5693_write_reg(ov5693, OV5693_CROP_START_X_H_REG, + (mode->crop_start_x >> 8) & 0x0f, &ret); + ov5693_write_reg(ov5693, OV5693_CROP_START_X_L_REG, + OV5693_CROP_START_X_L(mode->crop_start_x), &ret); + + /* Offset X */ + ov5693_write_reg(ov5693, OV5693_OFFSET_START_X_H_REG, + OV5693_OFFSET_START_X_H(mode->offset_x), &ret); + ov5693_write_reg(ov5693, OV5693_OFFSET_START_X_L_REG, + OV5693_OFFSET_START_X_L(mode->offset_x), &ret); + + /* Output Size X */ + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_X_H_REG, + OV5693_OUTPUT_SIZE_X_H(mode->output_size_x), &ret); + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_X_L_REG, + OV5693_OUTPUT_SIZE_X_L(mode->output_size_x), &ret); + + /* Crop End X */ + ov5693_write_reg(ov5693, OV5693_CROP_END_X_H_REG, + OV5693_CROP_END_X_H(mode->crop_end_x), &ret); + ov5693_write_reg(ov5693, OV5693_CROP_END_X_L_REG, + OV5693_CROP_END_X_L(mode->crop_end_x), &ret); + + /* Horizontal Total Size */ + ov5693_write_reg(ov5693, OV5693_TIMING_HTS_H_REG, + OV5693_TIMING_HTS_H(mode->hts), &ret); + ov5693_write_reg(ov5693, OV5693_TIMING_HTS_L_REG, + OV5693_TIMING_HTS_L(mode->hts), &ret); + + /* Crop Start Y */ + ov5693_write_reg(ov5693, OV5693_CROP_START_Y_H_REG, + OV5693_CROP_START_Y_H(mode->crop_start_y), &ret); + ov5693_write_reg(ov5693, OV5693_CROP_START_Y_L_REG, + OV5693_CROP_START_Y_L(mode->crop_start_y), &ret); + + /* Offset Y */ + ov5693_write_reg(ov5693, OV5693_OFFSET_START_Y_H_REG, + OV5693_OFFSET_START_Y_H(mode->offset_y), &ret); + ov5693_write_reg(ov5693, OV5693_OFFSET_START_Y_L_REG, + OV5693_OFFSET_START_Y_L(mode->offset_y), &ret); + + /* Output Size Y */ + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_Y_H_REG, + OV5693_OUTPUT_SIZE_Y_H(mode->output_size_y), &ret); + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_Y_L_REG, + OV5693_OUTPUT_SIZE_Y_L(mode->output_size_y), &ret); + + /* Crop End Y */ + ov5693_write_reg(ov5693, OV5693_CROP_END_Y_H_REG, + OV5693_CROP_END_Y_H(mode->crop_end_y), &ret); + ov5693_write_reg(ov5693, OV5693_CROP_END_Y_L_REG, + OV5693_CROP_END_Y_L(mode->crop_end_y), &ret); + + /* Vertical Total Size */ + ov5693_write_reg(ov5693, OV5693_TIMING_VTS_H_REG, + OV5693_TIMING_VTS_H(mode->vts), &ret); + ov5693_write_reg(ov5693, OV5693_TIMING_VTS_L_REG, + OV5693_TIMING_VTS_L(mode->vts), &ret); + + /* Subsample X increase */ + ov5693_write_reg(ov5693, OV5693_SUB_INC_X_REG, + ((mode->inc_x_odd << 4) & 0xf0) | + (mode->inc_x_even & 0x0f), &ret); + /* Subsample Y increase */ + ov5693_write_reg(ov5693, OV5693_SUB_INC_Y_REG, + ((mode->inc_y_odd << 4) & 0xf0) | + (mode->inc_y_even & 0x0f), &ret); + + if (ret) + return ret; + + /* Binning */ + ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, + OV5693_FORMAT1_VBIN_EN, + mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0); + if (ret) + return ret; + + ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, + OV5693_FORMAT2_HBIN_EN, + mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0); + if (ret) + return ret; + + /* Scaler */ + ret = ov5693_update_bits(ov5693, OV5693_ISP_CTRL2_REG, + OV5693_ISP_SCALE_ENABLE, + mode->scale_enable ? OV5693_ISP_SCALE_ENABLE : 0); + if (ret) + return ret; + + return ret; +} + static int ov5693_sw_standby(struct ov5693_device *ov5693, bool standby) { - return ov5693_write_reg(ov5693->client, OV5693_8BIT, OV5693_SW_STREAM, - standby ? OV5693_STOP_STREAMING : OV5693_START_STREAMING); + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_SW_STREAM_REG, + standby ? OV5693_STOP_STREAMING : OV5693_START_STREAMING, + &ret); + + return ret; } static int ov5693_sw_reset(struct ov5693_device *ov5693) { - return ov5693_write_reg(ov5693->client, OV5693_8BIT, OV5693_SW_RESET, - 0x01); + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_SW_RESET_REG, OV5693_SW_RESET, &ret); + + return ret; } static int ov5693_sensor_init(struct ov5693_device *ov5693) { - struct i2c_client *client = ov5693->client; int ret = 0; ret = ov5693_sw_reset(ov5693); if (ret) { - dev_err(&client->dev, "ov5693 reset err.\n"); + dev_err(ov5693->dev, "%s software reset error\n", __func__); return ret; } - ret = ov5693_write_reg_array(client, ov5693_global_setting); + ret = ov5693_write_reg_array(ov5693, &ov5693_global_setting); if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); + dev_err(ov5693->dev, "%s global settings error\n", __func__); return ret; } - ret = ov5693_write_reg_array(client, ov5693->mode->regs); + ret = ov5693_mode_configure(ov5693); if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); + dev_err(ov5693->dev, "%s mode configure error\n", __func__); return ret; } ret = ov5693_sw_standby(ov5693, true); if (ret) - dev_err(&client->dev, "ov5693 stream off error\n"); + dev_err(ov5693->dev, "%s software standby error\n", __func__); return ret; } @@ -774,10 +972,8 @@ static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies); clk_disable_unprepare(ov5693->clk); - gpiod_set_value_cansleep(ov5693->indicator_led, 0); } - static int ov5693_sensor_powerup(struct ov5693_device *ov5693) { int ret = 0; @@ -787,19 +983,18 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693) ret = clk_prepare_enable(ov5693->clk); if (ret) { - dev_err(&ov5693->client->dev, "Failed to enable clk\n"); + dev_err(ov5693->dev, "Failed to enable clk\n"); goto fail_power; } ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES, ov5693->supplies); if (ret) { - dev_err(&ov5693->client->dev, "Failed to enable regulators\n"); + dev_err(ov5693->dev, "Failed to enable regulators\n"); goto fail_power; } gpiod_set_value_cansleep(ov5693->reset, 0); gpiod_set_value_cansleep(ov5693->powerdown, 0); - gpiod_set_value_cansleep(ov5693->indicator_led, 1); usleep_range(20000, 25000); @@ -812,8 +1007,7 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693) static int __maybe_unused ov5693_sensor_suspend(struct device *dev) { - struct i2c_client *client = i2c_verify_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5693_device *ov5693 = to_ov5693_sensor(sd); int ret; @@ -834,8 +1028,7 @@ static int __maybe_unused ov5693_sensor_suspend(struct device *dev) static int __maybe_unused ov5693_sensor_resume(struct device *dev) { - struct i2c_client *client = i2c_verify_client(dev); - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct v4l2_subdev *sd = dev_get_drvdata(dev); struct ov5693_device *ov5693 = to_ov5693_sensor(sd); int ret; @@ -847,7 +1040,7 @@ static int __maybe_unused ov5693_sensor_resume(struct device *dev) ret = ov5693_sensor_init(ov5693); if (ret) { - dev_err(&client->dev, "ov5693 sensor init failure\n"); + dev_err(dev, "ov5693 sensor init failure\n"); goto err_power; } @@ -866,6 +1059,54 @@ static int __maybe_unused ov5693_sensor_resume(struct device *dev) return ret; } +static int ov5693_detect(struct ov5693_device *ov5693) +{ + u8 id_l = 0, id_h = 0; + u16 id = 0; + int ret; + + ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID_H, &id_h); + if (ret) { + dev_err(ov5693->dev, "sensor ID high byte = 0x%02x\n", id_h); + return -ENODEV; + } + + ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID_L, &id_l); + if (ret) { + dev_err(ov5693->dev, "sensor ID low byte = 0x%02x\n", id_l); + return -ENODEV; + } + + id = (id_h << 8) | id_l; + + if (id != OV5693_CHIP_ID) { + dev_err(ov5693->dev, "sensor ID mismatch. Found 0x%04x\n", id); + return -ENODEV; + } + + return 0; +} + +static int ov5693_verify_chip(struct ov5693_device *ov5693) +{ + int ret; + + mutex_lock(&ov5693->lock); + ret = ov5693_sensor_powerup(ov5693); + if (ret) + goto out; + + ret = ov5693_detect(ov5693); + +out: + ov5693_sensor_powerdown(ov5693); + mutex_unlock(&ov5693->lock); + + return ret; +} + +/* V4L2 Framework callbacks */ + static int ov5693_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) @@ -881,15 +1122,16 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd, mutex_lock(&ov5693->lock); - mode = v4l2_find_nearest_size(ov5693_res_video, ARRAY_SIZE(ov5693_res_video), - width, height, format->format.width, + mode = v4l2_find_nearest_size(ov5693_resolutions, + OV5693_NUM_RESOLUTIONS, output_size_x, + output_size_y, format->format.width, format->format.height); if (!mode) return -EINVAL; - format->format.width = mode->width; - format->format.height = mode->height; + format->format.width = mode->output_size_x; + format->format.height = mode->output_size_y; format->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { @@ -901,16 +1143,17 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd, /* Update limits and set FPS to default */ __v4l2_ctrl_modify_range(ov5693->ctrls.vblank, - mode->lines_per_frame - mode->height, - OV5693_TIMING_MAX_VTS - mode->height, - 1, mode->lines_per_frame - mode->height); + OV5693_TIMING_MIN_VTS, + OV5693_TIMING_MAX_VTS - mode->output_size_y, + 1, mode->vts - mode->output_size_y); __v4l2_ctrl_s_ctrl(ov5693->ctrls.vblank, - mode->lines_per_frame - mode->height); + mode->vts - mode->output_size_y); - hblank = mode->pixels_per_line - mode->width; - __v4l2_ctrl_modify_range(ov5693->ctrls.hblank, hblank, hblank, 1, hblank); + hblank = mode->hts - mode->output_size_x; + __v4l2_ctrl_modify_range(ov5693->ctrls.hblank, hblank, hblank, 1, + hblank); - exposure_max = mode->lines_per_frame - 8; + exposure_max = mode->vts - OV5693_INTEGRATION_TIME_MARGIN; __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, ov5693->ctrls.exposure->minimum, exposure_max, ov5693->ctrls.exposure->step, @@ -935,40 +1178,37 @@ __ov5693_get_pad_crop(struct ov5693_device *ov5693, struct v4l2_subdev_pad_confi return NULL; } + static int ov5693_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { - switch (sel->target) { - case V4L2_SEL_TGT_CROP: { - struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + switch (sel->target) { + case V4L2_SEL_TGT_CROP: mutex_lock(&ov5693->lock); - sel->r = *__ov5693_get_pad_crop(ov5693, cfg, sel->pad, - sel->which); + sel->r = *__ov5693_get_pad_crop(ov5693, cfg, sel->pad, sel->which); mutex_unlock(&ov5693->lock); - - return 0; - } - + break; case V4L2_SEL_TGT_NATIVE_SIZE: sel->r.top = 0; sel->r.left = 0; sel->r.width = OV5693_NATIVE_WIDTH; sel->r.height = OV5693_NATIVE_HEIGHT; - - return 0; - + break; + case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.top = OV5693_PIXEL_ARRAY_TOP; - sel->r.left = OV5693_PIXEL_ARRAY_LEFT; - sel->r.width = OV5693_PIXEL_ARRAY_WIDTH; - sel->r.height = OV5693_PIXEL_ARRAY_HEIGHT; - - return 0; + sel->r.top = OV5693_ACTIVE_START_TOP; + sel->r.left = OV5693_ACTIVE_START_LEFT; + sel->r.width = OV5693_ACTIVE_WIDTH; + sel->r.height = OV5693_ACTIVE_HEIGHT; + break; + default: + return -EINVAL; } - return -EINVAL; + return 0; } static int ov5693_get_fmt(struct v4l2_subdev *sd, @@ -984,61 +1224,25 @@ static int ov5693_get_fmt(struct v4l2_subdev *sd, if (!fmt) return -EINVAL; - fmt->width = ov5693->mode->width; - fmt->height = ov5693->mode->height; + fmt->width = ov5693->mode->output_size_x; + fmt->height = ov5693->mode->output_size_y; fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; return 0; } -static int ov5693_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_L, &low); - id = ((((u16)high) << 8) | (u16)low); - - if (id != OV5693_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_SUB_ID, &high); - revision = (u8)high & 0x0f; - - dev_info(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_info(&client->dev, "sensor_address = 0x%02x\n", client->addr); - dev_info(&client->dev, "detect ov5693 success\n"); - return 0; -} - static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) { struct ov5693_device *ov5693 = to_ov5693_sensor(sd); int ret; if (enable) { - ret = pm_runtime_get_sync(&ov5693->client->dev); + ret = pm_runtime_get_sync(ov5693->dev); if (ret < 0) goto err_power_down; } - ret = __v4l2_ctrl_handler_setup(&ov5693->ctrl_handler); + ret = __v4l2_ctrl_handler_setup(&ov5693->ctrls.handler); if (ret) goto err_power_down; @@ -1050,49 +1254,12 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) goto err_power_down; ov5693->streaming = !!enable; - /* power_off() here after streaming for regular PCs. */ if (!enable) - pm_runtime_put(&ov5693->client->dev); + pm_runtime_put(ov5693->dev); return 0; err_power_down: - pm_runtime_put_noidle(&ov5693->client->dev); - return ret; -} - -static int ov5693_s_config(struct v4l2_subdev *sd, int irq) -{ - struct ov5693_device *ov5693 = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - mutex_lock(&ov5693->lock); - ret = ov5693_sensor_powerup(ov5693); - if (ret) { - dev_err(&client->dev, "ov5693 power-up err.\n"); - goto fail_power_on; - } - - /* config & detect sensor */ - ret = ov5693_detect(client); - if (ret) { - dev_err(&client->dev, "ov5693_detect err s_config.\n"); - goto fail_power_on; - } - - ov5693->otp_data = ov5693_otp_read(sd); - - /* turn off sensor, after probed */ - ov5693_sensor_powerdown(ov5693); - - mutex_unlock(&ov5693->lock); - - return ret; - -fail_power_on: - ov5693_sensor_powerdown(ov5693); - dev_err(&client->dev, "sensor power-gating failed\n"); - mutex_unlock(&ov5693->lock); + pm_runtime_put_noidle(ov5693->dev); return ret; } @@ -1111,7 +1278,7 @@ static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index >= MAX_FMTS) + if (code->index >= OV5693_NUM_MBUS_FMTS) return -EINVAL; code->code = MEDIA_BUS_FMT_SBGGR10_1X10; @@ -1124,13 +1291,13 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd, { int index = fse->index; - if (index >= N_RES) + if (index >= OV5693_NUM_RESOLUTIONS) return -EINVAL; - fse->min_width = ov5693_res[index].width; - fse->min_height = ov5693_res[index].height; - fse->max_width = ov5693_res[index].width; - fse->max_height = ov5693_res[index].height; + fse->min_width = ov5693_resolutions[index].output_size_x; + fse->min_height = ov5693_resolutions[index].output_size_y; + fse->max_width = ov5693_resolutions[index].output_size_x; + fse->max_height = ov5693_resolutions[index].output_size_y; return 0; } @@ -1153,132 +1320,126 @@ static const struct v4l2_subdev_ops ov5693_ops = { .pad = &ov5693_pad_ops, }; -static int ov5693_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *ov5693 = to_ov5693_sensor(sd); - - dev_info(&client->dev, "%s...\n", __func__); - - v4l2_async_unregister_subdev(sd); - - media_entity_cleanup(&ov5693->sd.entity); - v4l2_ctrl_handler_free(&ov5693->ctrl_handler); - kfree(ov5693); - - return 0; -} +/* Sensor and Driver Configuration Functions */ static int ov5693_init_controls(struct ov5693_device *ov5693) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd); const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops; struct v4l2_fwnode_device_properties props; - int ret; - int hblank; - int vblank_max, vblank_min, vblank_def; + int vblank_max, vblank_def; int exposure_max; + int hblank; + int ret; - ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler, 8); - if (ret) { - ov5693_remove(client); + ret = v4l2_ctrl_handler_init(&ov5693->ctrls.handler, 14); + if (ret) return ret; - } /* link freq */ - ov5693->ctrls.link_freq = v4l2_ctrl_new_int_menu(&ov5693->ctrl_handler, + ov5693->ctrls.link_freq = v4l2_ctrl_new_int_menu(&ov5693->ctrls.handler, NULL, V4L2_CID_LINK_FREQ, 0, 0, link_freq_menu_items); if (ov5693->ctrls.link_freq) ov5693->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel rate */ - ov5693->ctrls.pixel_rate = v4l2_ctrl_new_std(&ov5693->ctrl_handler, NULL, + ov5693->ctrls.pixel_rate = v4l2_ctrl_new_std(&ov5693->ctrls.handler, NULL, V4L2_CID_PIXEL_RATE, 0, OV5693_PIXEL_RATE, 1, OV5693_PIXEL_RATE); - if (ov5693->ctrl_handler.error) { - ov5693_remove(client); - return ov5693->ctrl_handler.error; - } - /* Exposure */ - exposure_max = ov5693->mode->lines_per_frame - 8; - ov5693->ctrls.exposure = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, - V4L2_CID_EXPOSURE, 1, - exposure_max, 1, 123); + exposure_max = ov5693->mode->vts - OV5693_INTEGRATION_TIME_MARGIN; + ov5693->ctrls.exposure = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, + V4L2_CID_EXPOSURE, + OV5693_EXPOSURE_MIN, + exposure_max, + OV5693_EXPOSURE_STEP, + exposure_max); /* Gain */ - - ov5693->ctrls.analogue_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler, + ov5693->ctrls.analogue_gain = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, V4L2_CID_ANALOGUE_GAIN, - 1, 127, 1, 8); - ov5693->ctrls.digital_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, - V4L2_CID_DIGITAL_GAIN, 1, - 4095, 1, 1024); + OV5693_GAIN_MIN, + OV5693_GAIN_MAX, + OV5693_GAIN_STEP, + OV5693_GAIN_DEF); + ov5693->ctrls.digital_gain = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, + V4L2_CID_DIGITAL_GAIN, + OV5693_DIGITAL_GAIN_MIN, + OV5693_DIGITAL_GAIN_MAX, + OV5693_DIGITAL_GAIN_STEP, + OV5693_DIGITAL_GAIN_DEF); /* Flip */ - - ov5693->ctrls.hflip = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, + ov5693->ctrls.hflip = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - ov5693->ctrls.vflip = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, + ov5693->ctrls.vflip = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - hblank = ov5693->mode->pixels_per_line - ov5693->mode->width; - ov5693->ctrls.hblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, + hblank = ov5693->mode->hts - ov5693->mode->output_size_x; + ov5693->ctrls.hblank = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); if (ov5693->ctrls.hblank) ov5693->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - vblank_max = OV5693_TIMING_MAX_VTS - ov5693->mode->height; - vblank_def = ov5693->mode->lines_per_frame - ov5693->mode->height; - vblank_min = ov5693->mode->lines_per_frame - ov5693->mode->height; - ov5693->ctrls.vblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, - V4L2_CID_VBLANK, vblank_min, + vblank_max = OV5693_TIMING_MAX_VTS - ov5693->mode->output_size_y; + vblank_def = ov5693->mode->vts - ov5693->mode->output_size_y; + ov5693->ctrls.vblank = v4l2_ctrl_new_std(&ov5693->ctrls.handler, ops, + V4L2_CID_VBLANK, + OV5693_TIMING_MIN_VTS, vblank_max, 1, vblank_def); + ov5693->ctrls.test_pattern = v4l2_ctrl_new_std_menu_items( + &ov5693->ctrls.handler, ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5693_test_pattern_menu) - 1, + 0, 0, ov5693_test_pattern_menu); + + if (ov5693->ctrls.handler.error) { + dev_err(ov5693->dev, "Error initialising v4l2 ctrls\n"); + ret = ov5693->ctrls.handler.error; + goto err_free_handler; + } + /* set properties from fwnode (e.g. rotation, orientation) */ - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov5693->dev, &props); if (ret) - return ret; + goto err_free_handler; - ret = v4l2_ctrl_new_fwnode_properties(&ov5693->ctrl_handler, ops, &props); + ret = v4l2_ctrl_new_fwnode_properties(&ov5693->ctrls.handler, ops, + &props); if (ret) - return ret; + goto err_free_handler; /* Use same lock for controls as for everything else. */ - ov5693->ctrl_handler.lock = &ov5693->lock; - ov5693->sd.ctrl_handler = &ov5693->ctrl_handler; + ov5693->ctrls.handler.lock = &ov5693->lock; + ov5693->sd.ctrl_handler = &ov5693->ctrls.handler; return 0; + +err_free_handler: + v4l2_ctrl_handler_free(&ov5693->ctrls.handler); + return ret; } static int ov5693_configure_gpios(struct ov5693_device *ov5693) { - ov5693->reset = devm_gpiod_get_optional(&ov5693->client->dev, "reset", - GPIOD_OUT_HIGH); - if (IS_ERR(ov5693->reset)) { - dev_err(&ov5693->client->dev, "Couldn't find reset GPIO\n"); - return PTR_ERR(ov5693->reset); - } - - ov5693->powerdown = devm_gpiod_get_optional(&ov5693->client->dev, "powerdown", - GPIOD_OUT_HIGH); - if (IS_ERR(ov5693->powerdown)) { - dev_err(&ov5693->client->dev, "Couldn't find powerdown GPIO\n"); - return PTR_ERR(ov5693->powerdown); - } - - ov5693->indicator_led = devm_gpiod_get_optional(&ov5693->client->dev, "indicator-led", - GPIOD_OUT_HIGH); - if (IS_ERR(ov5693->indicator_led)) { - dev_err(&ov5693->client->dev, "Couldn't find indicator-led GPIO\n"); - return PTR_ERR(ov5693->indicator_led); - } - - return 0; + ov5693->reset = devm_gpiod_get_optional(ov5693->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5693->reset)) { + dev_err(ov5693->dev, "Error fetching reset GPIO\n"); + return PTR_ERR(ov5693->reset); + } + + ov5693->powerdown = devm_gpiod_get_optional(ov5693->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5693->powerdown)) { + dev_err(ov5693->dev, "Error fetching powerdown GPIO\n"); + return PTR_ERR(ov5693->powerdown); + } + + return 0; } static int ov5693_get_regulators(struct ov5693_device *ov5693) @@ -1288,24 +1449,30 @@ static int ov5693_get_regulators(struct ov5693_device *ov5693) for (i = 0; i < OV5693_NUM_SUPPLIES; i++) ov5693->supplies[i].supply = ov5693_supply_names[i]; - return devm_regulator_bulk_get(&ov5693->client->dev, - OV5693_NUM_SUPPLIES, + return devm_regulator_bulk_get(ov5693->dev, OV5693_NUM_SUPPLIES, ov5693->supplies); } static int ov5693_probe(struct i2c_client *client) { + struct fwnode_handle *fwnode = dev_fwnode(&client->dev); + struct fwnode_handle *endpoint; struct ov5693_device *ov5693; u32 clk_rate; int ret = 0; - dev_info(&client->dev, "%s() called", __func__); + endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!endpoint && !IS_ERR_OR_NULL(fwnode->secondary)) + endpoint = fwnode_graph_get_next_endpoint(fwnode->secondary, NULL); + if (!endpoint) + return -EPROBE_DEFER; ov5693 = devm_kzalloc(&client->dev, sizeof(*ov5693), GFP_KERNEL); if (!ov5693) return -ENOMEM; ov5693->client = client; + ov5693->dev = &client->dev; mutex_init(&ov5693->lock); @@ -1314,7 +1481,7 @@ static int ov5693_probe(struct i2c_client *client) ov5693->clk = devm_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov5693->clk)) { dev_err(&client->dev, "Error getting clock\n"); - return -EINVAL; + return PTR_ERR(ov5693->clk); } clk_rate = clk_get_rate(ov5693->clk); @@ -1325,53 +1492,67 @@ static int ov5693_probe(struct i2c_client *client) } ret = ov5693_configure_gpios(ov5693); - if (ret) - goto out_free; + if (ret) + return ret; ret = ov5693_get_regulators(ov5693); - if (ret) - goto out_put_reset; + if (ret) { + dev_err(&client->dev, "Error fetching regulators\n"); + return ret; + } - ret = ov5693_s_config(&ov5693->sd, client->irq); + ret = ov5693_verify_chip(ov5693); if (ret) - goto out_put_reset; + return ret; ov5693->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov5693->pad.flags = MEDIA_PAD_FL_SOURCE; - ov5693->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; ov5693->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ov5693->mode = &ov5693_res_video[N_RES_VIDEO-1]; + ov5693->mode = &ov5693_resolutions[OV5693_NUM_RESOLUTIONS - 1]; ret = ov5693_init_controls(ov5693); if (ret) - ov5693_remove(client); + return ret; ret = media_entity_pads_init(&ov5693->sd.entity, 1, &ov5693->pad); if (ret) - ov5693_remove(client); + goto err_ctrl_handler_free; pm_runtime_enable(&client->dev); pm_runtime_set_suspended(&client->dev); ret = v4l2_async_register_subdev_sensor_common(&ov5693->sd); if (ret) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); - goto media_entity_cleanup; + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto err_media_entity_cleanup; } return ret; -media_entity_cleanup: - pm_runtime_disable(&client->dev); +err_media_entity_cleanup: media_entity_cleanup(&ov5693->sd.entity); -out_put_reset: - gpiod_put(ov5693->reset); -out_free: - v4l2_device_unregister_subdev(&ov5693->sd); - kfree(ov5693); +err_ctrl_handler_free: + v4l2_ctrl_handler_free(&ov5693->ctrls.handler); + + pm_runtime_disable(&client->dev); return ret; } +static int ov5693_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&ov5693->sd.entity); + v4l2_ctrl_handler_free(&ov5693->ctrls.handler); + mutex_destroy(&ov5693->lock); + pm_runtime_disable(ov5693->dev); + + return 0; +} + static const struct dev_pm_ops ov5693_pm_ops = { SET_RUNTIME_PM_OPS(ov5693_sensor_suspend, ov5693_sensor_resume, NULL) }; diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h deleted file mode 100644 index 0377853f8b2bf..0000000000000 --- a/drivers/media/i2c/ov5693.h +++ /dev/null @@ -1,990 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for OmniVision OV5693 5M camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * 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. - * - * - */ - -#ifndef __OV5693_H__ -#define __OV5693_H__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OV5693_HID "INT33BE" - -/* - * FIXME: non-preview resolutions are currently broken - */ -#define ENABLE_NON_PREVIEW 1 - -/* Defines for register writes and register array processing */ -#define I2C_MSG_LENGTH 0x2 - -#define MAX_FMTS 1 - -#define OV5693_ID 0x5690 - -/* - * OV5693 System control registers - */ -#define OV5693_SW_RESET 0x0103 -#define OV5693_SW_STREAM 0x0100 - -#define OV5693_SC_CMMN_CHIP_ID_H 0x300A -#define OV5693_SC_CMMN_CHIP_ID_L 0x300B -#define OV5693_SC_CMMN_SUB_ID 0x302A /* process, version*/ - -/* -*Bit[3:0] Bit[19:16] of exposure, -*remaining 16 bits lies in Reg0x3501&Reg0x3502 -*/ -#define OV5693_EXPOSURE_H 0x3500 -#define OV5693_EXPOSURE_M 0x3501 -#define OV5693_EXPOSURE_L 0x3502 -/*Bit[1:0] means Bit[9:8] of gain*/ -#define OV5693_AGC_H 0x350A -#define OV5693_AGC_L 0x350B /*Bit[7:0] of gain*/ - -/*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV5693_TIMING_HTS_H 0x380C -/*High 8-bit, and low 8-bit HTS address is 0x380d*/ -#define OV5693_TIMING_HTS_L 0x380D -/*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV5693_TIMING_VTS_H 0x380e -/*High 8-bit, and low 8-bit HTS address is 0x380f*/ -#define OV5693_TIMING_VTS_L 0x380f - -#define OV5693_TIMING_MAX_VTS 0xffff - -#define OV5693_MWB_RED_GAIN_H 0x3400 -#define OV5693_MWB_GREEN_GAIN_H 0x3402 -#define OV5693_MWB_BLUE_GAIN_H 0x3404 -#define OV5693_MWB_GAIN_MAX 0x0fff - -#define OV5693_START_STREAMING 0x01 -#define OV5693_STOP_STREAMING 0x00 - -/* Defines for OTP Data Registers */ -#define OV5693_FRAME_OFF_NUM 0x4202 -#define OV5693_OTP_BYTE_MAX 32 //change to 32 as needed by otpdata -#define OV5693_OTP_SHORT_MAX 16 -#define OV5693_OTP_START_ADDR 0x3D00 -#define OV5693_OTP_END_ADDR 0x3D0F -#define OV5693_OTP_DATA_SIZE 320 -#define OV5693_OTP_PROGRAM_REG 0x3D80 -#define OV5693_OTP_READ_REG 0x3D81 // 1:Enable 0:disable -#define OV5693_OTP_BANK_REG 0x3D84 //otp bank and mode -#define OV5693_OTP_READY_REG_DONE 1 -#define OV5693_OTP_BANK_MAX 28 -#define OV5693_OTP_BANK_SIZE 16 //16 bytes per bank -#define OV5693_OTP_READ_ONETIME 16 -#define OV5693_OTP_MODE_READ 1 - -#define OV5693_XVCLK_FREQ 19200000 - -/* link freq and pixel rate required for IPU3 */ -#define OV5693_LINK_FREQ_400MHZ 400000000 -/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample - * To avoid integer overflow, dividing by bits_per_sample first. - */ -#define OV5693_PIXEL_RATE (OV5693_LINK_FREQ_400MHZ / 10) * 2 * 2 -static const s64 link_freq_menu_items[] = { - OV5693_LINK_FREQ_400MHZ -}; - -#define OV5693_NUM_SUPPLIES 2 -static const char * const ov5693_supply_names[] = { - "avdd", - "dovdd", -}; - -struct regval_list { - u16 reg_num; - u8 value; -}; - -struct ov5693_resolution { - u8 *desc; - const struct ov5693_reg *regs; - int res; - u32 width; - u32 height; - int fps; - int pix_clk_freq; - u16 pixels_per_line; - u16 lines_per_frame; - u8 bin_factor_x; - u8 bin_factor_y; - u8 bin_mode; - bool used; - - /* Analog crop rectangle. */ - struct v4l2_rect crop; -}; - -struct ov5693_format { - u8 *desc; - u32 pixelformat; - struct ov5693_reg *regs; -}; - -enum vcm_type { - VCM_UNKNOWN, - VCM_AD5823, - VCM_DW9714, -}; - -/* - * ov5693 device structure. - */ -struct ov5693_device { - struct i2c_client *client; - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_mbus_framefmt format; - struct mutex lock; - struct v4l2_ctrl_handler ctrl_handler; - - struct gpio_desc *reset; - struct gpio_desc *powerdown; - struct gpio_desc *indicator_led; - struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; - struct clk *clk; - - /* Current mode */ - const struct ov5693_resolution *mode; - bool streaming; - - struct camera_sensor_platform_data *platform_data; - ktime_t timestamp_t_focus_abs; - int vt_pix_clk_freq_mhz; - int run_mode; - int otp_size; - u8 *otp_data; - u32 focus; - s16 number_of_steps; - u8 res; - u8 type; - bool vcm_update; - enum vcm_type vcm; - - bool has_vcm; - - struct ov5693_v4l2_ctrls { - struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *pixel_rate; - struct v4l2_ctrl *exposure; - struct v4l2_ctrl *analogue_gain; - struct v4l2_ctrl *digital_gain; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *vblank; - } ctrls; - -}; - -enum ov5693_tok_type { - OV5693_8BIT = 0x0001, - OV5693_16BIT = 0x0002, - OV5693_32BIT = 0x0004, - OV5693_TOK_TERM = 0xf000, /* terminating token for reg list */ - OV5693_TOK_DELAY = 0xfe00, /* delay token for reg list */ - OV5693_TOK_MASK = 0xfff0 -}; - -/** - * struct ov5693_reg - MI sensor register format - * @type: type of the register - * @reg: 16-bit offset to register - * @val: 8/16/32-bit register value - * - * Define a structure for sensor register initialization values - */ -struct ov5693_reg { - enum ov5693_tok_type type; - u16 reg; - u32 val; /* @set value for read/mod/write, @mask */ -}; - -#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd) - -#define OV5693_MAX_WRITE_BUF_SIZE 30 - -struct ov5693_write_buffer { - u16 addr; - u8 data[OV5693_MAX_WRITE_BUF_SIZE]; -}; - -struct ov5693_write_ctrl { - int index; - struct ov5693_write_buffer buffer; -}; - -static struct ov5693_reg const ov5693_global_setting[] = { - {OV5693_8BIT, 0x0103, 0x01}, - {OV5693_8BIT, 0x3001, 0x0a}, - {OV5693_8BIT, 0x3002, 0x80}, - {OV5693_8BIT, 0x3006, 0x00}, - {OV5693_8BIT, 0x3011, 0x21}, - {OV5693_8BIT, 0x3012, 0x09}, - {OV5693_8BIT, 0x3013, 0x10}, - {OV5693_8BIT, 0x3014, 0x00}, - {OV5693_8BIT, 0x3015, 0x08}, - {OV5693_8BIT, 0x3016, 0xf0}, - {OV5693_8BIT, 0x3017, 0xf0}, - {OV5693_8BIT, 0x3018, 0xf0}, - {OV5693_8BIT, 0x301b, 0xb4}, - {OV5693_8BIT, 0x301d, 0x02}, - {OV5693_8BIT, 0x3021, 0x00}, - {OV5693_8BIT, 0x3022, 0x01}, - {OV5693_8BIT, 0x3028, 0x44}, - {OV5693_8BIT, 0x3098, 0x02}, - {OV5693_8BIT, 0x3099, 0x19}, - {OV5693_8BIT, 0x309a, 0x02}, - {OV5693_8BIT, 0x309b, 0x01}, - {OV5693_8BIT, 0x309c, 0x00}, - {OV5693_8BIT, 0x30a0, 0xd2}, - {OV5693_8BIT, 0x30a2, 0x01}, - {OV5693_8BIT, 0x30b2, 0x00}, - {OV5693_8BIT, 0x30b3, 0x7d}, - {OV5693_8BIT, 0x30b4, 0x03}, - {OV5693_8BIT, 0x30b5, 0x04}, - {OV5693_8BIT, 0x30b6, 0x01}, - {OV5693_8BIT, 0x3104, 0x21}, - {OV5693_8BIT, 0x3106, 0x00}, - {OV5693_8BIT, 0x3400, 0x04}, - {OV5693_8BIT, 0x3401, 0x00}, - {OV5693_8BIT, 0x3402, 0x04}, - {OV5693_8BIT, 0x3403, 0x00}, - {OV5693_8BIT, 0x3404, 0x04}, - {OV5693_8BIT, 0x3405, 0x00}, - {OV5693_8BIT, 0x3406, 0x01}, - {OV5693_8BIT, 0x3500, 0x00}, - {OV5693_8BIT, 0x3503, 0x07}, - {OV5693_8BIT, 0x3504, 0x00}, - {OV5693_8BIT, 0x3505, 0x00}, - {OV5693_8BIT, 0x3506, 0x00}, - {OV5693_8BIT, 0x3507, 0x02}, - {OV5693_8BIT, 0x3508, 0x00}, - {OV5693_8BIT, 0x3509, 0x10}, - {OV5693_8BIT, 0x350a, 0x00}, - {OV5693_8BIT, 0x350b, 0x40}, - {OV5693_8BIT, 0x3601, 0x0a}, - {OV5693_8BIT, 0x3602, 0x38}, - {OV5693_8BIT, 0x3612, 0x80}, - {OV5693_8BIT, 0x3620, 0x54}, - {OV5693_8BIT, 0x3621, 0xc7}, - {OV5693_8BIT, 0x3622, 0x0f}, - {OV5693_8BIT, 0x3625, 0x10}, - {OV5693_8BIT, 0x3630, 0x55}, - {OV5693_8BIT, 0x3631, 0xf4}, - {OV5693_8BIT, 0x3632, 0x00}, - {OV5693_8BIT, 0x3633, 0x34}, - {OV5693_8BIT, 0x3634, 0x02}, - {OV5693_8BIT, 0x364d, 0x0d}, - {OV5693_8BIT, 0x364f, 0xdd}, - {OV5693_8BIT, 0x3660, 0x04}, - {OV5693_8BIT, 0x3662, 0x10}, - {OV5693_8BIT, 0x3663, 0xf1}, - {OV5693_8BIT, 0x3665, 0x00}, - {OV5693_8BIT, 0x3666, 0x20}, - {OV5693_8BIT, 0x3667, 0x00}, - {OV5693_8BIT, 0x366a, 0x80}, - {OV5693_8BIT, 0x3680, 0xe0}, - {OV5693_8BIT, 0x3681, 0x00}, - {OV5693_8BIT, 0x3700, 0x42}, - {OV5693_8BIT, 0x3701, 0x14}, - {OV5693_8BIT, 0x3702, 0xa0}, - {OV5693_8BIT, 0x3703, 0xd8}, - {OV5693_8BIT, 0x3704, 0x78}, - {OV5693_8BIT, 0x3705, 0x02}, - {OV5693_8BIT, 0x370a, 0x00}, - {OV5693_8BIT, 0x370b, 0x20}, - {OV5693_8BIT, 0x370c, 0x0c}, - {OV5693_8BIT, 0x370d, 0x11}, - {OV5693_8BIT, 0x370e, 0x00}, - {OV5693_8BIT, 0x370f, 0x40}, - {OV5693_8BIT, 0x3710, 0x00}, - {OV5693_8BIT, 0x371a, 0x1c}, - {OV5693_8BIT, 0x371b, 0x05}, - {OV5693_8BIT, 0x371c, 0x01}, - {OV5693_8BIT, 0x371e, 0xa1}, - {OV5693_8BIT, 0x371f, 0x0c}, - {OV5693_8BIT, 0x3721, 0x00}, - {OV5693_8BIT, 0x3724, 0x10}, - {OV5693_8BIT, 0x3726, 0x00}, - {OV5693_8BIT, 0x372a, 0x01}, - {OV5693_8BIT, 0x3730, 0x10}, - {OV5693_8BIT, 0x3738, 0x22}, - {OV5693_8BIT, 0x3739, 0xe5}, - {OV5693_8BIT, 0x373a, 0x50}, - {OV5693_8BIT, 0x373b, 0x02}, - {OV5693_8BIT, 0x373c, 0x41}, - {OV5693_8BIT, 0x373f, 0x02}, - {OV5693_8BIT, 0x3740, 0x42}, - {OV5693_8BIT, 0x3741, 0x02}, - {OV5693_8BIT, 0x3742, 0x18}, - {OV5693_8BIT, 0x3743, 0x01}, - {OV5693_8BIT, 0x3744, 0x02}, - {OV5693_8BIT, 0x3747, 0x10}, - {OV5693_8BIT, 0x374c, 0x04}, - {OV5693_8BIT, 0x3751, 0xf0}, - {OV5693_8BIT, 0x3752, 0x00}, - {OV5693_8BIT, 0x3753, 0x00}, - {OV5693_8BIT, 0x3754, 0xc0}, - {OV5693_8BIT, 0x3755, 0x00}, - {OV5693_8BIT, 0x3756, 0x1a}, - {OV5693_8BIT, 0x3758, 0x00}, - {OV5693_8BIT, 0x3759, 0x0f}, - {OV5693_8BIT, 0x376b, 0x44}, - {OV5693_8BIT, 0x375c, 0x04}, - {OV5693_8BIT, 0x3774, 0x10}, - {OV5693_8BIT, 0x3776, 0x00}, - {OV5693_8BIT, 0x377f, 0x08}, - {OV5693_8BIT, 0x3780, 0x22}, - {OV5693_8BIT, 0x3781, 0x0c}, - {OV5693_8BIT, 0x3784, 0x2c}, - {OV5693_8BIT, 0x3785, 0x1e}, - {OV5693_8BIT, 0x378f, 0xf5}, - {OV5693_8BIT, 0x3791, 0xb0}, - {OV5693_8BIT, 0x3795, 0x00}, - {OV5693_8BIT, 0x3796, 0x64}, - {OV5693_8BIT, 0x3797, 0x11}, - {OV5693_8BIT, 0x3798, 0x30}, - {OV5693_8BIT, 0x3799, 0x41}, - {OV5693_8BIT, 0x379a, 0x07}, - {OV5693_8BIT, 0x379b, 0xb0}, - {OV5693_8BIT, 0x379c, 0x0c}, - {OV5693_8BIT, 0x37c5, 0x00}, - {OV5693_8BIT, 0x37c6, 0x00}, - {OV5693_8BIT, 0x37c7, 0x00}, - {OV5693_8BIT, 0x37c9, 0x00}, - {OV5693_8BIT, 0x37ca, 0x00}, - {OV5693_8BIT, 0x37cb, 0x00}, - {OV5693_8BIT, 0x37de, 0x00}, - {OV5693_8BIT, 0x37df, 0x00}, - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3810, 0x00}, - {OV5693_8BIT, 0x3812, 0x00}, - {OV5693_8BIT, 0x3823, 0x00}, - {OV5693_8BIT, 0x3824, 0x00}, - {OV5693_8BIT, 0x3825, 0x00}, - {OV5693_8BIT, 0x3826, 0x00}, - {OV5693_8BIT, 0x3827, 0x00}, - {OV5693_8BIT, 0x382a, 0x04}, - {OV5693_8BIT, 0x3a04, 0x06}, - {OV5693_8BIT, 0x3a05, 0x14}, - {OV5693_8BIT, 0x3a06, 0x00}, - {OV5693_8BIT, 0x3a07, 0xfe}, - {OV5693_8BIT, 0x3b00, 0x00}, - {OV5693_8BIT, 0x3b02, 0x00}, - {OV5693_8BIT, 0x3b03, 0x00}, - {OV5693_8BIT, 0x3b04, 0x00}, - {OV5693_8BIT, 0x3b05, 0x00}, - {OV5693_8BIT, 0x3e07, 0x20}, - {OV5693_8BIT, 0x4000, 0x08}, - {OV5693_8BIT, 0x4001, 0x04}, - {OV5693_8BIT, 0x4002, 0x45}, - {OV5693_8BIT, 0x4004, 0x08}, - {OV5693_8BIT, 0x4005, 0x18}, - {OV5693_8BIT, 0x4006, 0x20}, - {OV5693_8BIT, 0x4008, 0x24}, - {OV5693_8BIT, 0x4009, 0x10}, - {OV5693_8BIT, 0x400c, 0x00}, - {OV5693_8BIT, 0x400d, 0x00}, - {OV5693_8BIT, 0x4058, 0x00}, - {OV5693_8BIT, 0x404e, 0x37}, - {OV5693_8BIT, 0x404f, 0x8f}, - {OV5693_8BIT, 0x4058, 0x00}, - {OV5693_8BIT, 0x4101, 0xb2}, - {OV5693_8BIT, 0x4303, 0x00}, - {OV5693_8BIT, 0x4304, 0x08}, - {OV5693_8BIT, 0x4307, 0x31}, - {OV5693_8BIT, 0x4311, 0x04}, - {OV5693_8BIT, 0x4315, 0x01}, - {OV5693_8BIT, 0x4511, 0x05}, - {OV5693_8BIT, 0x4512, 0x01}, - {OV5693_8BIT, 0x4806, 0x00}, - {OV5693_8BIT, 0x4816, 0x52}, - {OV5693_8BIT, 0x481f, 0x30}, - {OV5693_8BIT, 0x4826, 0x2c}, - {OV5693_8BIT, 0x4831, 0x64}, - {OV5693_8BIT, 0x4d00, 0x04}, - {OV5693_8BIT, 0x4d01, 0x71}, - {OV5693_8BIT, 0x4d02, 0xfd}, - {OV5693_8BIT, 0x4d03, 0xf5}, - {OV5693_8BIT, 0x4d04, 0x0c}, - {OV5693_8BIT, 0x4d05, 0xcc}, - {OV5693_8BIT, 0x4837, 0x0a}, - {OV5693_8BIT, 0x5000, 0x06}, - {OV5693_8BIT, 0x5001, 0x01}, - {OV5693_8BIT, 0x5003, 0x20}, - {OV5693_8BIT, 0x5046, 0x0a}, - {OV5693_8BIT, 0x5013, 0x00}, - {OV5693_8BIT, 0x5046, 0x0a}, - {OV5693_8BIT, 0x5780, 0x1c}, - {OV5693_8BIT, 0x5786, 0x20}, - {OV5693_8BIT, 0x5787, 0x10}, - {OV5693_8BIT, 0x5788, 0x18}, - {OV5693_8BIT, 0x578a, 0x04}, - {OV5693_8BIT, 0x578b, 0x02}, - {OV5693_8BIT, 0x578c, 0x02}, - {OV5693_8BIT, 0x578e, 0x06}, - {OV5693_8BIT, 0x578f, 0x02}, - {OV5693_8BIT, 0x5790, 0x02}, - {OV5693_8BIT, 0x5791, 0xff}, - {OV5693_8BIT, 0x5842, 0x01}, - {OV5693_8BIT, 0x5843, 0x2b}, - {OV5693_8BIT, 0x5844, 0x01}, - {OV5693_8BIT, 0x5845, 0x92}, - {OV5693_8BIT, 0x5846, 0x01}, - {OV5693_8BIT, 0x5847, 0x8f}, - {OV5693_8BIT, 0x5848, 0x01}, - {OV5693_8BIT, 0x5849, 0x0c}, - {OV5693_8BIT, 0x5e00, 0x00}, - {OV5693_8BIT, 0x5e10, 0x0c}, - {OV5693_8BIT, 0x0100, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; - -#if ENABLE_NON_PREVIEW - - -/* - * 1296x976 30fps 17ms VBlanking 2lane 10Bit (Scaling) -*DS from 2592x1952 -*/ -static struct ov5693_reg const ov5693_1296x976[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0x00}, - - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - - {OV5693_8BIT, 0x3808, 0x05}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x03}, - {OV5693_8BIT, 0x380b, 0xD0}, - - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - - {OV5693_8BIT, 0x3810, 0x00}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3812, 0x00}, - {OV5693_8BIT, 0x3813, 0x02}, - - {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ - {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_TOK_TERM, 0, 0} - -}; - -/* - * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2564x1956 - */ -static struct ov5693_reg const ov5693_336x256[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x01}, - {OV5693_8BIT, 0x3809, 0x50}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0x00}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x1E}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2368x1956 - */ -static struct ov5693_reg const ov5693_368x304[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3808, 0x01}, - {OV5693_8BIT, 0x3809, 0x70}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0x30}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x80}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; - -/* - * ov5693_192x160 30fps 17ms VBlanking 2lane 10Bit (Scaling) - DS from 2460x1956 - */ -static struct ov5693_reg const ov5693_192x160[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x80}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - {OV5693_8BIT, 0x3808, 0x00}, - {OV5693_8BIT, 0x3809, 0xC0}, - {OV5693_8BIT, 0x380a, 0x00}, - {OV5693_8BIT, 0x380b, 0xA0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x40}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_736x496[] = { - {OV5693_8BIT, 0x3501, 0x3d}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe6}, - {OV5693_8BIT, 0x3709, 0xc7}, - {OV5693_8BIT, 0x3803, 0x68}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0x3b}, - {OV5693_8BIT, 0x3808, 0x02}, - {OV5693_8BIT, 0x3809, 0xe0}, - {OV5693_8BIT, 0x380a, 0x01}, - {OV5693_8BIT, 0x380b, 0xf0}, - {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /*vts*/ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x08}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x31}, - {OV5693_8BIT, 0x3815, 0x31}, - {OV5693_8BIT, 0x3820, 0x04}, - {OV5693_8BIT, 0x3821, 0x1f}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 976x556 30fps 8.8ms VBlanking 2lane 10Bit (Scaling) - */ -#if ENABLE_NON_PREVIEW - -/*DS from 2624x1492*/ -static struct ov5693_reg const ov5693_1296x736[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0x00}, - - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xA3}, - - {OV5693_8BIT, 0x3808, 0x05}, - {OV5693_8BIT, 0x3809, 0x10}, - {OV5693_8BIT, 0x380a, 0x02}, - {OV5693_8BIT, 0x380b, 0xe0}, - - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - - {OV5693_8BIT, 0x3813, 0xE8}, - - {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ - {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_1636p_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa7}, - {OV5693_8BIT, 0x3808, 0x06}, - {OV5693_8BIT, 0x3809, 0x64}, - {OV5693_8BIT, 0x380a, 0x04}, - {OV5693_8BIT, 0x380b, 0x48}, - {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /*vts*/ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x02}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 1940x1096 30fps 8.8ms VBlanking 2lane 10bit (Scaling) - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_1940x1096[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa7}, - {OV5693_8BIT, 0x3808, 0x07}, - {OV5693_8BIT, 0x3809, 0x94}, - {OV5693_8BIT, 0x380a, 0x04}, - {OV5693_8BIT, 0x380b, 0x48}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x02}, - {OV5693_8BIT, 0x3813, 0x02}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x80}, - {OV5693_TOK_TERM, 0, 0} -}; - -static struct ov5693_reg const ov5693_2592x1456_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, - {OV5693_8BIT, 0x3801, 0x00}, - {OV5693_8BIT, 0x3802, 0x00}, - {OV5693_8BIT, 0x3803, 0xf0}, - {OV5693_8BIT, 0x3804, 0x0a}, - {OV5693_8BIT, 0x3805, 0x3f}, - {OV5693_8BIT, 0x3806, 0x06}, - {OV5693_8BIT, 0x3807, 0xa4}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x20}, - {OV5693_8BIT, 0x380a, 0x05}, - {OV5693_8BIT, 0x380b, 0xb0}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 2592x1944 30fps 0.6ms VBlanking 2lane 10Bit - */ -#if ENABLE_NON_PREVIEW -static struct ov5693_reg const ov5693_2592x1944_30fps[] = { - {OV5693_8BIT, 0x3501, 0x7b}, - {OV5693_8BIT, 0x3502, 0x00}, - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3803, 0x00}, - {OV5693_8BIT, 0x3806, 0x07}, - {OV5693_8BIT, 0x3807, 0xa3}, - {OV5693_8BIT, 0x3808, 0x0a}, - {OV5693_8BIT, 0x3809, 0x20}, - {OV5693_8BIT, 0x380a, 0x07}, - {OV5693_8BIT, 0x380b, 0x98}, - {OV5693_8BIT, 0x380c, 0x0a}, - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3811, 0x10}, - {OV5693_8BIT, 0x3813, 0x00}, - {OV5693_8BIT, 0x3814, 0x11}, - {OV5693_8BIT, 0x3815, 0x11}, - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_TOK_TERM, 0, 0} -}; -#endif - -/* - * 3:2 Full FOV Output, expected FOV Res: 2560x1706 - * ISP Effect Res: 720x480 - * Sensor out: 736x496, DS From 2616x1764 - */ -static struct ov5693_reg const ov5693_736x496_30fps[] = { - {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */ - {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */ - {OV5693_8BIT, 0x3708, 0xe2}, - {OV5693_8BIT, 0x3709, 0xc3}, - {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */ - {OV5693_8BIT, 0x3801, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */ - {OV5693_8BIT, 0x3803, 0x62}, /* 98 */ - {OV5693_8BIT, 0x3804, 0x0a}, /* TIMING_X_ADDR_END */ - {OV5693_8BIT, 0x3805, 0x3b}, /* 2619 */ - {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */ - {OV5693_8BIT, 0x3807, 0x43}, /* 1859 */ - {OV5693_8BIT, 0x3808, 0x02}, /* TIMING_X_OUTPUT_SIZE */ - {OV5693_8BIT, 0x3809, 0xe0}, /* 736 */ - {OV5693_8BIT, 0x380a, 0x01}, /* TIMING_Y_OUTPUT_SIZE */ - {OV5693_8BIT, 0x380b, 0xf0}, /* 496 */ - {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */ - {OV5693_8BIT, 0x380d, 0x80}, - {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */ - {OV5693_8BIT, 0x380f, 0xc0}, - {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */ - {OV5693_8BIT, 0x3811, 0x02}, /* 2 */ - {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */ - {OV5693_8BIT, 0x3813, 0x00}, /* 0 */ - {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */ - {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */ - {OV5693_8BIT, 0x3820, 0x00}, - {OV5693_8BIT, 0x3821, 0x1e}, - {OV5693_8BIT, 0x5002, 0x00}, - {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */ - {OV5693_TOK_TERM, 0, 0} -}; - -struct ov5693_resolution ov5693_res_video[] = { - { - .desc = "ov5693_736x496_30fps", - .width = 736, - .height = 496, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, - .regs = ov5693_736x496, - }, - { - .desc = "ov5693_336x256_30fps", - .width = 336, - .height = 256, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, - .regs = ov5693_336x256, - }, - { - .desc = "ov5693_368x304_30fps", - .width = 368, - .height = 304, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, - .regs = ov5693_368x304, - }, - { - .desc = "ov5693_192x160_30fps", - .width = 192, - .height = 160, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 1, - .regs = ov5693_192x160, - }, - { - .desc = "ov5693_1296x736_30fps", - .width = 1296, - .height = 736, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, - .regs = ov5693_1296x736, - }, - { - .desc = "ov5693_1296x976_30fps", - .width = 1296, - .height = 976, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 2, - .bin_factor_y = 2, - .bin_mode = 0, - .regs = ov5693_1296x976, - }, - { - .desc = "ov5693_1636P_30fps", - .width = 1636, - .height = 1096, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .regs = ov5693_1636p_30fps, - }, - { - .desc = "ov5693_1080P_30fps", - .width = 1940, - .height = 1096, - .fps = 30, - .pix_clk_freq = 160, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .regs = ov5693_1940x1096, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1456, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .regs = ov5693_2592x1456_30fps, - }, - { - .desc = "ov5693_5M_30fps", - .width = 2592, - .height = 1944, - .pix_clk_freq = 160, - .fps = 30, - .used = 0, - .pixels_per_line = 2688, - .lines_per_frame = 1984, - .bin_factor_x = 1, - .bin_factor_y = 1, - .bin_mode = 0, - .regs = ov5693_2592x1944_30fps, - .crop = { - .left = 0, - .top = 0, - .width = 2592, - .height = 1944 - }, - }, -}; - -#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video)) -#endif - -static struct ov5693_resolution *ov5693_res = ov5693_res_video; -static unsigned long N_RES = N_RES_VIDEO; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9a1f648efde06..bdfce7b156216 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1520,6 +1520,24 @@ config MFD_TPS65217 This driver can also be built as a module. If so, the module will be called tps65217. +config MFD_TPS68470 + bool "TI TPS68470 Power Management / LED chips" + depends on ACPI && PCI && I2C=y + depends on I2C_DESIGNWARE_PLATFORM=y + select MFD_CORE + select REGMAP_I2C + help + If you say yes here you get support for the TPS68470 series of + Power Management / LED chips. + + These include voltage regulators, LEDs and other features + that are often used in portable devices. + + This option is a bool as it provides an ACPI operation + region, which must be available before any of the devices + using this are probed. This option also configures the + designware-i2c driver to be built-in, for the same reason. + config MFD_TI_LP873X tristate "TI LP873X Power Management IC" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 5994e812f4798..14fdb188af022 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o +obj-$(CONFIG_MFD_TPS68470) += tps68470.o obj-$(CONFIG_MFD_TPS80031) += tps80031.o obj-$(CONFIG_MENELAUS) += menelaus.o diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c new file mode 100644 index 0000000000000..4a4df4ffd18c3 --- /dev/null +++ b/drivers/mfd/tps68470.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TPS68470 chip Parent driver + * + * Copyright (C) 2017 Intel Corporation + * + * Authors: + * Rajmohan Mani + * Tianshu Qiu + * Jian Xu Zheng + * Yuning Pu + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell tps68470s[] = { + { .name = "tps68470-gpio" }, + { .name = "tps68470_pmic_opregion" }, +}; + +static const struct regmap_config tps68470_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS68470_REG_MAX, +}; + +static int tps68470_chip_init(struct device *dev, struct regmap *regmap) +{ + unsigned int version; + int ret; + + /* Force software reset */ + ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK); + if (ret) + return ret; + + ret = regmap_read(regmap, TPS68470_REG_REVID, &version); + if (ret) { + dev_err(dev, "Failed to read revision register: %d\n", ret); + return ret; + } + + dev_info(dev, "TPS68470 REVID: 0x%x\n", version); + + return 0; +} + +static int tps68470_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "devm_regmap_init_i2c Error %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + i2c_set_clientdata(client, regmap); + + ret = tps68470_chip_init(dev, regmap); + if (ret < 0) { + dev_err(dev, "TPS68470 Init Error %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tps68470s, + ARRAY_SIZE(tps68470s), NULL, 0, NULL); + if (ret < 0) { + dev_err(dev, "devm_mfd_add_devices failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct acpi_device_id tps68470_acpi_ids[] = { + {"INT3472"}, + {}, +}; + +static struct i2c_driver tps68470_driver = { + .driver = { + .name = "tps68470", + .acpi_match_table = tps68470_acpi_ids, + }, + .probe_new = tps68470_probe, +}; +builtin_i2c_driver(tps68470_driver); diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index 8dc2c267bcd68..f8c691720caf3 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -706,7 +706,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) * For now let's thus default power/wakeup to false. */ device_set_wakeup_capable(&serdev->dev, true); - acpi_walk_dep_device_list(ssh); + acpi_dev_flag_dependency_met(ssh); return 0; diff --git a/drivers/platform/surface/surface3_power.c b/drivers/platform/surface/surface3_power.c index cc4f9cba68563..ad895285d3e9c 100644 --- a/drivers/platform/surface/surface3_power.c +++ b/drivers/platform/surface/surface3_power.c @@ -478,7 +478,7 @@ static int mshw0011_install_space_handler(struct i2c_client *client) return -ENOMEM; } - acpi_walk_dep_device_list(handle); + acpi_dev_flag_dependency_met(handle); return 0; } diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index ef9c1f8e8336f..e18dc4e30af23 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -835,7 +835,7 @@ static int san_probe(struct platform_device *pdev) if (status) goto err_install_dev; - acpi_walk_dep_device_list(san); + acpi_dev_flag_dependency_met(san); return 0; err_install_dev: diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 916b077df2d51..9739d30951b65 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -844,30 +844,7 @@ config INTEL_CHT_INT33FE device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m for Type-C device. -config INTEL_SKL_INT3472 - tristate "Intel SkyLake ACPI INT3472 Driver" - depends on X86 && ACPI - select REGMAP_I2C - help - This driver adds support for the INT3472 ACPI devices found on some - Intel SkyLake devices. - - There are 3 kinds of INT3472 ACPI device possible; two for devices - designed for Windows (either with or without a physical tps68470 - PMIC) and one designed for Chrome OS. This driver handles all three - situations by discovering information it needs to discern them at - runtime. - - If your device was designed for Chrome OS, this driver will provide - an ACPI operation region, which must be available before any of the - devices using this are probed. For this reason, you should select Y - if your device was designed for ChromeOS. This option also configures - the designware-i2c driver to be built-in, for the same reason. - - Say Y or M here if you have a SkyLake device designed for use - with Windows or ChromeOS. Say N here if you are not sure. - - The module will be named "intel-skl-int3472" +source "drivers/platform/x86/intel-int3472/Kconfig" config INTEL_HID_EVENT tristate "INTEL HID Event" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 3cefe67761af3..2293b6c3d1c29 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -86,11 +86,7 @@ obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o -obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472.o -intel_skl_int3472-objs := intel_skl_int3472_common.o \ - intel_skl_int3472_discrete.o \ - intel_skl_int3472_tps68470.o - +obj-$(CONFIG_INTEL_SKL_INT3472) += intel-int3472/ obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o # MSI diff --git a/drivers/platform/x86/intel-int3472/Kconfig b/drivers/platform/x86/intel-int3472/Kconfig new file mode 100644 index 0000000000000..b94622245c216 --- /dev/null +++ b/drivers/platform/x86/intel-int3472/Kconfig @@ -0,0 +1,31 @@ +config INTEL_SKL_INT3472 + tristate "Intel SkyLake ACPI INT3472 Driver" + depends on ACPI + depends on REGULATOR + depends on GPIOLIB + depends on COMMON_CLK && CLKDEV_LOOKUP + depends on I2C + select MFD_CORE + select REGMAP_I2C + help + This driver adds support for the INT3472 ACPI devices found on some + Intel SkyLake devices. + + The INT3472 is an Intel camera power controller, a logical device + found on some Skylake-based systems that can map to different + hardware devices depending on the platform. On machines + designed for Chrome OS, it maps to a TPS68470 camera PMIC. On + machines designed for Windows, it maps to either a TP68470 + camera PMIC, a uP6641Q sensor PMIC, or a set of discrete GPIOs + and power gates. + + If your device was designed for Chrome OS, this driver will provide + an ACPI OpRegion, which must be available before any of the devices + using it are probed. For this reason, you should select Y if your + device was designed for ChromeOS. For the same reason the + I2C_DESIGNWARE_PLATFORM option must be set to Y too. + + Say Y or M here if you have a SkyLake device designed for use + with Windows or ChromeOS. Say N here if you are not sure. + + The module will be named "intel-skl-int3472" diff --git a/drivers/platform/x86/intel-int3472/Makefile b/drivers/platform/x86/intel-int3472/Makefile new file mode 100644 index 0000000000000..c887ee7d52ca2 --- /dev/null +++ b/drivers/platform/x86/intel-int3472/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472.o +intel_skl_int3472-objs := intel_skl_int3472_common.o \ + intel_skl_int3472_discrete.o \ + intel_skl_int3472_tps68470.o diff --git a/drivers/platform/x86/intel_skl_int3472_common.c b/drivers/platform/x86/intel-int3472/intel_skl_int3472_common.c similarity index 92% rename from drivers/platform/x86/intel_skl_int3472_common.c rename to drivers/platform/x86/intel-int3472/intel_skl_int3472_common.c index 549d211979e15..f61166b6c4973 100644 --- a/drivers/platform/x86/intel_skl_int3472_common.c +++ b/drivers/platform/x86/intel-int3472/intel_skl_int3472_common.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "intel_skl_int3472_common.h" @@ -20,10 +21,8 @@ union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, return ERR_PTR(-ENODEV); obj = buffer.pointer; - if (!obj) { - dev_err(&adev->dev, "ACPI device has no %s object\n", id); + if (!obj) return ERR_PTR(-ENODEV); - } if (obj->type != ACPI_TYPE_BUFFER) { dev_err(&adev->dev, "%s object is not an ACPI buffer\n", id); @@ -58,7 +57,7 @@ int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) static const struct acpi_device_id int3472_device_id[] = { { "INT3472", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, int3472_device_id); @@ -89,12 +88,8 @@ static int skl_int3472_init(void) ret = i2c_register_driver(THIS_MODULE, &int3472_tps68470); if (ret) - goto err_unregister_plat_drv; - - return 0; + platform_driver_unregister(&int3472_discrete); -err_unregister_plat_drv: - platform_driver_unregister(&int3472_discrete); return ret; } module_init(skl_int3472_init); diff --git a/drivers/platform/x86/intel_skl_int3472_common.h b/drivers/platform/x86/intel-int3472/intel_skl_int3472_common.h similarity index 67% rename from drivers/platform/x86/intel_skl_int3472_common.h rename to drivers/platform/x86/intel-int3472/intel_skl_int3472_common.h index 860c849b77696..9169356cd5222 100644 --- a/drivers/platform/x86/intel_skl_int3472_common.h +++ b/drivers/platform/x86/intel-int3472/intel_skl_int3472_common.h @@ -1,45 +1,48 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Author: Dan Scally */ -#include + +#ifndef _INTEL_SKL_INT3472_H +#define _INTEL_SKL_INT3472_H + #include #include #include +#include #include /* PMIC GPIO Types */ #define INT3472_GPIO_TYPE_RESET 0x00 #define INT3472_GPIO_TYPE_POWERDOWN 0x01 -#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c #define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b +#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c #define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d + #define INT3472_PDEV_MAX_NAME_LEN 23 #define INT3472_MAX_SENSOR_GPIOS 3 -#define GPIO_REGULATOR_NAME_LENGTH 27 + +#define GPIO_REGULATOR_NAME_LENGTH 21 #define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9 #define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86 -#define INT3472_REGULATOR(_NAME, _SUPPLY, _OPS) \ +#define INT3472_REGULATOR(_name, _supply, _ops) \ (const struct regulator_desc) { \ - .name = _NAME, \ - .supply_name = _SUPPLY, \ - .id = 0, \ + .name = _name, \ + .supply_name = _supply, \ .type = REGULATOR_VOLTAGE, \ - .ops = _OPS, \ + .ops = _ops, \ .owner = THIS_MODULE, \ } -#define INT3472_GPIO_FUNCTION_REMAP(_PIN, _FUNCTION) \ - (const struct int3472_gpio_function_remap) { \ - .documented = _PIN, \ - .actual = _FUNCTION \ - } - #define to_int3472_clk(hw) \ container_of(hw, struct int3472_gpio_clock, clk_hw) #define to_int3472_device(clk) \ - container_of(clk, struct int3472_device, clock) + container_of(clk, struct int3472_discrete_device, clock) + +struct platform_device; +struct i2c_client; +struct acpi_device; struct int3472_cldb { u8 version; @@ -56,51 +59,52 @@ struct int3472_cldb { u8 reserved[28]; }; -struct int3472_gpio_regulator { - char regulator_name[GPIO_REGULATOR_NAME_LENGTH]; - char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH]; - struct gpio_desc *gpio; - struct regulator_dev *rdev; - struct regulator_desc rdesc; +struct int3472_gpio_function_remap { + char *documented; + char *actual; }; -struct int3472_gpio_clock { - struct clk *clk; - struct clk_hw clk_hw; - struct clk_lookup *cl; - struct gpio_desc *gpio; +struct int3472_sensor_config { + const char *sensor_module_name; + struct regulator_consumer_supply supply_map; + const struct int3472_gpio_function_remap *function_maps; }; -struct int3472_device { +struct int3472_discrete_device { struct acpi_device *adev; - struct platform_device *pdev; + struct device *dev; struct acpi_device *sensor; - char *sensor_name; + const char *sensor_name; + + struct int3472_sensor_config *sensor_config; + + struct int3472_gpio_regulator { + char regulator_name[GPIO_REGULATOR_NAME_LENGTH]; + char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH]; + struct gpio_desc *gpio; + struct regulator_dev *rdev; + struct regulator_desc rdesc; + } regulator; + + struct int3472_gpio_clock { + struct clk *clk; + struct clk_hw clk_hw; + struct clk_lookup *cl; + struct gpio_desc *ena_gpio; + struct gpio_desc *led_gpio; + u32 frequency; + } clock; unsigned int n_gpios; /* how many GPIOs have we seen */ - - struct int3472_gpio_regulator regulator; - struct int3472_gpio_clock clock; - unsigned int n_sensor_gpios; /* how many have we mapped to sensor */ - bool gpios_mapped; struct gpiod_lookup_table gpios; }; -struct int3472_gpio_function_remap { - char *documented; - char *actual; -}; - -struct int3472_sensor_config { - char *sensor_module_name; - struct regulator_consumer_supply supply_map; - const struct int3472_gpio_function_remap *function_maps; -}; - int skl_int3472_discrete_probe(struct platform_device *pdev); int skl_int3472_discrete_remove(struct platform_device *pdev); int skl_int3472_tps68470_probe(struct i2c_client *client); union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id); int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb); + +#endif diff --git a/drivers/platform/x86/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel-int3472/intel_skl_int3472_discrete.c similarity index 58% rename from drivers/platform/x86/intel_skl_int3472_discrete.c rename to drivers/platform/x86/intel-int3472/intel_skl_int3472_discrete.c index 98eb1ec3399ef..2ede8b4b1f0a6 100644 --- a/drivers/platform/x86/intel_skl_int3472_discrete.c +++ b/drivers/platform/x86/intel-int3472/intel_skl_int3472_discrete.c @@ -3,21 +3,34 @@ #include #include +#include #include #include #include #include +#include #include #include +#include #include "intel_skl_int3472_common.h" -/* 79234640-9e10-4fea-a5c1-b5aa8b19756f */ +/* + * 79234640-9e10-4fea-a5c1-b5aa8b19756f + * This _DSM GUID returns information about the GPIO lines mapped to a + * discrete INT3472 device. Function number 1 returns a count of the GPIO + * lines that are mapped. Subsequent functions return 32 bit ints encoding + * information about the GPIO line, including its purpose. + */ static const guid_t int3472_gpio_guid = GUID_INIT(0x79234640, 0x9e10, 0x4fea, 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f); -/* 822ace8f-2814-4174-a56b-5f029fe079ee */ +/* + * 822ace8f-2814-4174-a56b-5f029fe079ee + * This _DSM GUID returns a string from the sensor device, which acts as a + * module identifier. + */ static const guid_t cio2_sensor_module_guid = GUID_INIT(0x822ace8f, 0x2814, 0x4174, 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee); @@ -26,7 +39,8 @@ static const guid_t cio2_sensor_module_guid = * Here follows platform specific mapping information that we can pass to * the functions mapping resources to the sensors. Where the sensors have * a power enable pin defined in DSDT we need to provide a supply name so - * the sensor drivers can find the regulator. Optionally, we can provide a + * the sensor drivers can find the regulator. The device name will be derived + * from the sensor's ACPI device within the code. Optionally, we can provide a * NULL terminated array of function name mappings to deal with any platform * specific deviations from the documented behaviour of GPIOs. * @@ -35,8 +49,8 @@ static const guid_t cio2_sensor_module_guid = */ static const struct int3472_gpio_function_remap ov2680_gpio_function_remaps[] = { - INT3472_GPIO_FUNCTION_REMAP("reset", NULL), - INT3472_GPIO_FUNCTION_REMAP("powerdown", "reset"), + { "reset", NULL }, + { "powerdown", "reset" }, { } }; @@ -44,9 +58,9 @@ static struct int3472_sensor_config int3472_sensor_configs[] = { /* Lenovo Miix 510-12ISK - OV2680, Front */ { "GNDF140809R", { 0 }, ov2680_gpio_function_remaps}, /* Lenovo Miix 510-12ISK - OV5648, Rear */ - { "GEFF150023R", REGULATOR_SUPPLY("avdd", "i2c-OVTI5648:00"), NULL}, + { "GEFF150023R", REGULATOR_SUPPLY("avdd", NULL), NULL}, /* Surface Go 1&2 - OV5693, Front */ - { "YHCU", REGULATOR_SUPPLY("avdd", "i2c-INT33BE:00"), NULL}, + { "YHCU", REGULATOR_SUPPLY("avdd", NULL), NULL}, }; /* @@ -56,63 +70,69 @@ static struct int3472_sensor_config int3472_sensor_configs[] = { */ static const struct regulator_ops int3472_gpio_regulator_ops = { 0 }; -static int skl_int3472_clk_enable(struct clk_hw *hw) +static int skl_int3472_clk_prepare(struct clk_hw *hw) { struct int3472_gpio_clock *clk = to_int3472_clk(hw); - gpiod_set_value(clk->gpio, 1); + gpiod_set_value(clk->ena_gpio, 1); + if (clk->led_gpio) + gpiod_set_value(clk->led_gpio, 1); return 0; } -static void skl_int3472_clk_disable(struct clk_hw *hw) +static void skl_int3472_clk_unprepare(struct clk_hw *hw) { struct int3472_gpio_clock *clk = to_int3472_clk(hw); - gpiod_set_value(clk->gpio, 0); + gpiod_set_value(clk->ena_gpio, 0); + if (clk->led_gpio) + gpiod_set_value(clk->led_gpio, 0); } -static int skl_int3472_clk_prepare(struct clk_hw *hw) +static int skl_int3472_clk_enable(struct clk_hw *hw) { /* - * We're just turning a GPIO on to enable, so nothing to do here, but - * we want to provide the op so prepare_enable() works. + * We're just turning a GPIO on to enable, which operation has the + * potential to sleep. Given enable cannot sleep, but prepare can, + * we toggle the GPIO in prepare instead. Thus, nothing to do here. */ return 0; } -static void skl_int3472_clk_unprepare(struct clk_hw *hw) +static void skl_int3472_clk_disable(struct clk_hw *hw) { /* Likewise, nothing to do here... */ } -static unsigned int skl_int3472_get_clk_frequency(struct int3472_device *int3472) +static unsigned int skl_int3472_get_clk_frequency(struct int3472_discrete_device *int3472) { union acpi_object *obj; unsigned int ret = 0; obj = skl_int3472_get_acpi_buffer(int3472->sensor, "SSDB"); if (IS_ERR(obj)) - goto out_free_buff; /* report rate as 0 on error */ + return 0; /* report rate as 0 on error */ if (obj->buffer.length < CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET + sizeof(u32)) { - dev_err(&int3472->pdev->dev, "The buffer is too small\n"); + dev_err(int3472->dev, "The buffer is too small\n"); goto out_free_buff; } - ret = *(u32*)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET); + ret = *(u32 *)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET); out_free_buff: kfree(obj); return ret; } -static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { struct int3472_gpio_clock *clk = to_int3472_clk(hw); - struct int3472_device *int3472 = to_int3472_device(clk); + struct int3472_discrete_device *int3472 = to_int3472_device(clk); - return skl_int3472_get_clk_frequency(int3472); + return int3472->clock.frequency; } static const struct clk_ops skl_int3472_clock_ops = { @@ -124,35 +144,34 @@ static const struct clk_ops skl_int3472_clock_ops = { }; static struct int3472_sensor_config * -skl_int3472_get_sensor_module_config(struct int3472_device *int3472) +skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472) { - unsigned int i = ARRAY_SIZE(int3472_sensor_configs); - struct int3472_sensor_config *ret; + struct int3472_sensor_config *ret = NULL; union acpi_object *obj; + unsigned int i; obj = acpi_evaluate_dsm_typed(int3472->sensor->handle, &cio2_sensor_module_guid, 0x00, 0x01, NULL, ACPI_TYPE_STRING); if (!obj) { - dev_err(&int3472->pdev->dev, + dev_err(int3472->dev, "Failed to get sensor module string from _DSM\n"); return ERR_PTR(-ENODEV); } if (obj->string.type != ACPI_TYPE_STRING) { - dev_err(&int3472->pdev->dev, + dev_err(int3472->dev, "Sensor _DSM returned a non-string value\n"); ret = ERR_PTR(-EINVAL); goto out_free_obj; } - ret = ERR_PTR(-ENODEV); - while (i--) { + for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) { if (!strcmp(int3472_sensor_configs[i].sensor_module_name, obj->string.pointer)) { ret = &int3472_sensor_configs[i]; - goto out_free_obj; + break; } } @@ -161,41 +180,39 @@ skl_int3472_get_sensor_module_config(struct int3472_device *int3472) return ret; } -static int skl_int3472_map_gpio_to_sensor(struct int3472_device *int3472, +static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472, struct acpi_resource *ares, char *func, u32 polarity) { char *path = ares->data.gpio.resource_source.string_ptr; - struct int3472_sensor_config *sensor_config; - struct gpiod_lookup table_entry; + const struct int3472_sensor_config *sensor_config; + struct gpiod_lookup *table_entry; struct acpi_device *adev; acpi_handle handle; acpi_status status; int ret; - sensor_config = skl_int3472_get_sensor_module_config(int3472); - if (!IS_ERR(sensor_config) && sensor_config->function_maps) { - unsigned int i = 0; + if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { + dev_warn(int3472->dev, "Too many GPIOs mapped\n"); + return -EINVAL; + } - while (sensor_config->function_maps[i].documented) { - if (!strcmp(func, sensor_config->function_maps[i].documented)) { - func = sensor_config->function_maps[i].actual; + sensor_config = int3472->sensor_config; + if (!IS_ERR_OR_NULL(sensor_config) && sensor_config->function_maps) { + const struct int3472_gpio_function_remap *remap = + sensor_config->function_maps; + for (; remap->documented; ++remap) + if (!strcmp(func, remap->documented)) { + func = remap->actual; break; } - - i++; - } } + /* Functions mapped to NULL should not be mapped to the sensor */ if (!func) return 0; - if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) { - dev_warn(&int3472->pdev->dev, "Too many GPIOs mapped\n"); - return -EINVAL; - } - status = acpi_get_handle(NULL, path, &handle); if (ACPI_FAILURE(status)) return -EINVAL; @@ -204,63 +221,91 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_device *int3472, if (ret) return -ENODEV; - table_entry = (struct gpiod_lookup)GPIO_LOOKUP_IDX(acpi_dev_name(adev), - ares->data.gpio.pin_table[0], - func, 0, polarity); - - memcpy(&int3472->gpios.table[int3472->n_sensor_gpios], &table_entry, - sizeof(table_entry)); + table_entry = &int3472->gpios.table[int3472->n_sensor_gpios]; + table_entry->key = acpi_dev_name(adev); + table_entry->chip_hwnum = ares->data.gpio.pin_table[0]; + table_entry->con_id = func; + table_entry->idx = 0; + table_entry->flags = polarity; int3472->n_sensor_gpios++; return 0; } -static int skl_int3472_register_clock(struct int3472_device *int3472, - struct acpi_resource *ares) +static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, + struct acpi_resource *ares, u8 type) { char *path = ares->data.gpio.resource_source.string_ptr; - struct clk_init_data init = { 0 }; + struct gpio_desc *gpio; + + switch (type) { + case INT3472_GPIO_TYPE_CLK_ENABLE: + gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0], + "int3472,clk-enable"); + if (IS_ERR(gpio)) + return (PTR_ERR(gpio)); + + int3472->clock.ena_gpio = gpio; + break; + case INT3472_GPIO_TYPE_PRIVACY_LED: + gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0], + "int3472,privacy-led"); + if (IS_ERR(gpio)) + return (PTR_ERR(gpio)); + + int3472->clock.led_gpio = gpio; + break; + default: + dev_err(int3472->dev, "Invalid GPIO type 0x%hx for clock\n", + type); + break; + } + + return 0; +} + +static int skl_int3472_register_clock(struct int3472_discrete_device *int3472) +{ + struct clk_init_data init = { + .ops = &skl_int3472_clock_ops, + .flags = CLK_GET_RATE_NOCACHE, + }; int ret = 0; init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(int3472->adev)); - init.ops = &skl_int3472_clock_ops; - init.flags |= CLK_GET_RATE_NOCACHE; + if (!init.name) + return -ENOMEM; - int3472->clock.gpio = acpi_get_gpiod(path, - ares->data.gpio.pin_table[0]); - if (IS_ERR(int3472->clock.gpio)) { - ret = PTR_ERR(int3472->clock.gpio); - goto out_free_init_name; - } + int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472); int3472->clock.clk_hw.init = &init; int3472->clock.clk = clk_register(&int3472->adev->dev, &int3472->clock.clk_hw); if (IS_ERR(int3472->clock.clk)) { ret = PTR_ERR(int3472->clock.clk); - goto err_put_gpio; + goto out_free_init_name; } - int3472->clock.cl = clkdev_create(int3472->clock.clk, "xvclk", + int3472->clock.cl = clkdev_create(int3472->clock.clk, NULL, int3472->sensor_name); - if (IS_ERR_OR_NULL(int3472->clock.cl)) + if (!int3472->clock.cl) { + ret = -ENOMEM; goto err_unregister_clk; + } goto out_free_init_name; err_unregister_clk: clk_unregister(int3472->clock.clk); -err_put_gpio: - gpiod_put(int3472->clock.gpio); out_free_init_name: kfree(init.name); return ret; } -static int skl_int3472_register_regulator(struct int3472_device *int3472, +static int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, struct acpi_resource *ares) { char *path = ares->data.gpio.resource_source.string_ptr; @@ -269,24 +314,25 @@ static int skl_int3472_register_regulator(struct int3472_device *int3472, struct regulator_config cfg = { }; int ret; - sensor_config = skl_int3472_get_sensor_module_config(int3472); + sensor_config = int3472->sensor_config; if (IS_ERR_OR_NULL(sensor_config)) { - dev_err(&int3472->pdev->dev, "No sensor module config\n"); + dev_err(int3472->dev, "No sensor module config\n"); return PTR_ERR(sensor_config); } if (!sensor_config->supply_map.supply) { - dev_err(&int3472->pdev->dev, "No supply name defined\n"); + dev_err(int3472->dev, "No supply name defined\n"); return -ENODEV; } - init_data.supply_regulator = NULL; init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS; init_data.num_consumer_supplies = 1; + sensor_config->supply_map.dev_name = int3472->sensor_name; init_data.consumer_supplies = &sensor_config->supply_map; snprintf(int3472->regulator.regulator_name, - GPIO_REGULATOR_NAME_LENGTH, "int3472-discrete-regulator"); + sizeof(int3472->regulator.regulator_name), "%s-regulator", + acpi_dev_name(int3472->adev)); snprintf(int3472->regulator.supply_name, GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0"); @@ -296,9 +342,10 @@ static int skl_int3472_register_regulator(struct int3472_device *int3472, &int3472_gpio_regulator_ops); int3472->regulator.gpio = acpi_get_gpiod(path, - ares->data.gpio.pin_table[0]); + ares->data.gpio.pin_table[0], + "int3472,regulator"); if (IS_ERR(int3472->regulator.gpio)) { - dev_err(&int3472->pdev->dev, "Failed to get GPIO line\n"); + dev_err(int3472->dev, "Failed to get regulator GPIO lines\n"); return PTR_ERR(int3472->regulator.gpio); } @@ -322,9 +369,9 @@ static int skl_int3472_register_regulator(struct int3472_device *int3472, } /** - * skl_int3472_handle_gpio_resources: maps PMIC resources to consuming sensor + * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor * @ares: A pointer to a &struct acpi_resource - * @data: A pointer to a &struct int3472_device + * @data: A pointer to a &struct int3472_discrete_device * * This function handles GPIO resources that are against an INT3472 * ACPI device, by checking the value of the corresponding _DSM entry. @@ -340,8 +387,8 @@ static int skl_int3472_register_regulator(struct int3472_device *int3472, * There are some known platform specific quirks where that does not quite * hold up; for example where a pin with type 0x01 (Power down) is mapped to * a sensor pin that performs a reset function or entries in _CRS and _DSM that - * do not actually correspond to a physical connection. These will be handled by - * the mapping sub-functions. + * do not actually correspond to a physical connection. These will be handled + * by the mapping sub-functions. * * GPIOs will either be mapped directly to the sensor device or else used * to create clocks and regulators via the usual frameworks. @@ -355,13 +402,16 @@ static int skl_int3472_register_regulator(struct int3472_device *int3472, static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, void *data) { - struct int3472_device *int3472 = data; + struct int3472_discrete_device *int3472 = data; + u16 pin = ares->data.gpio.pin_table[0]; union acpi_object *obj; + char *err_msg; int ret = 0; + u8 type; if (ares->type != ACPI_RESOURCE_TYPE_GPIO || ares->data.gpio.connection_type != ACPI_RESOURCE_GPIO_TYPE_IO) - return EINVAL; /* Deliberately positive so parsing continues */ + return 1; /* Deliberately positive so parsing continues */ /* * n_gpios + 2 because the index of this _DSM function is 1-based and @@ -373,81 +423,87 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, NULL, ACPI_TYPE_INTEGER); if (!obj) { - dev_warn(&int3472->pdev->dev, - "No _DSM entry for this GPIO pin\n"); - return ENODEV; + dev_warn(int3472->dev, "No _DSM entry for GPIO pin %u\n", pin); + return 1; } - switch (obj->integer.value & 0xff) { + type = obj->integer.value & 0xff; + + switch (type) { case INT3472_GPIO_TYPE_RESET: ret = skl_int3472_map_gpio_to_sensor(int3472, ares, "reset", GPIO_ACTIVE_LOW); if (ret) - dev_err(&int3472->pdev->dev, - "Failed to map reset pin to sensor\n"); + err_msg = "Failed to map reset pin to sensor\n"; break; case INT3472_GPIO_TYPE_POWERDOWN: - ret = skl_int3472_map_gpio_to_sensor(int3472, ares, "powerdown", + ret = skl_int3472_map_gpio_to_sensor(int3472, ares, + "powerdown", GPIO_ACTIVE_LOW); if (ret) - dev_err(&int3472->pdev->dev, - "Failed to map powerdown pin to sensor\n"); + err_msg = "Failed to map powerdown pin to sensor\n"; break; case INT3472_GPIO_TYPE_CLK_ENABLE: - ret = skl_int3472_register_clock(int3472, ares); + case INT3472_GPIO_TYPE_PRIVACY_LED: + ret = skl_int3472_map_gpio_to_clk(int3472, ares, type); if (ret) - dev_err(&int3472->pdev->dev, - "Failed to map clock to sensor\n"); + err_msg = "Failed to map GPIO to clock\n"; break; case INT3472_GPIO_TYPE_POWER_ENABLE: ret = skl_int3472_register_regulator(int3472, ares); - if (ret) { - dev_err(&int3472->pdev->dev, - "Failed to map regulator to sensor\n"); - } - - break; - case INT3472_GPIO_TYPE_PRIVACY_LED: - ret = skl_int3472_map_gpio_to_sensor(int3472, ares, - "indicator-led", - GPIO_ACTIVE_HIGH); if (ret) - dev_err(&int3472->pdev->dev, - "Failed to map indicator led to sensor\n"); + err_msg = "Failed to map regulator to sensor\n"; break; default: - dev_warn(&int3472->pdev->dev, - "GPIO type 0x%llx unknown; the sensor may not work\n", - (obj->integer.value & 0xff)); - ret = EINVAL; + dev_warn(int3472->dev, + "GPIO type 0x%02x unknown; the sensor may not work\n", + type); + ret = 1; + break; } + if (ret < 0 && ret != -EPROBE_DEFER) + dev_err(int3472->dev, err_msg); + int3472->n_gpios++; ACPI_FREE(obj); return ret; } -static int skl_int3472_parse_crs(struct int3472_device *int3472) +static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472) { struct list_head resource_list; - int ret = 0; + int ret; INIT_LIST_HEAD(&resource_list); + int3472->sensor_config = skl_int3472_get_sensor_module_config(int3472); + ret = acpi_dev_get_resources(int3472->adev, &resource_list, skl_int3472_handle_gpio_resources, int3472); + if (ret) + goto out_free_res_list; - if (!ret) { - gpiod_add_lookup_table(&int3472->gpios); - int3472->gpios_mapped = true; + if (int3472->clock.ena_gpio) { + ret = skl_int3472_register_clock(int3472); + if (ret) + goto out_free_res_list; + } else { + if (int3472->clock.led_gpio) + dev_warn(int3472->dev, + "No clk GPIO. The privacy LED won't work\n"); } + int3472->gpios.dev_id = int3472->sensor_name; + gpiod_add_lookup_table(&int3472->gpios); + +out_free_res_list: acpi_dev_free_resource_list(&resource_list); return ret; @@ -456,67 +512,76 @@ static int skl_int3472_parse_crs(struct int3472_device *int3472) int skl_int3472_discrete_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); - struct int3472_device *int3472; + struct int3472_discrete_device *int3472; struct int3472_cldb cldb; - int ret = 0; + int ret; ret = skl_int3472_fill_cldb(adev, &cldb); - if (ret || cldb.control_logic_type != 1) + if (ret) { + dev_err(&pdev->dev, "Couldn't fill CLDB structure\n"); + return ret; + } + + if (cldb.control_logic_type != 1) { + dev_err(&pdev->dev, "Unsupported control logic type %u\n", + cldb.control_logic_type); return -EINVAL; + } - int3472 = kzalloc(sizeof(*int3472) + - ((INT3472_MAX_SENSOR_GPIOS + 1) * sizeof(struct gpiod_lookup)), - GFP_KERNEL); + /* Max num GPIOs we've seen plus a terminator */ + int3472 = devm_kzalloc(&pdev->dev, struct_size(int3472, gpios.table, + INT3472_MAX_SENSOR_GPIOS + 1), GFP_KERNEL); if (!int3472) return -ENOMEM; int3472->adev = adev; - int3472->pdev = pdev; + int3472->dev = &pdev->dev; platform_set_drvdata(pdev, int3472); - int3472->sensor = acpi_dev_get_next_dep_dev(adev, NULL); - if (!int3472->sensor) { + int3472->sensor = acpi_dev_get_dependent_dev(adev); + if (IS_ERR_OR_NULL(int3472->sensor)) { dev_err(&pdev->dev, - "This INT3472 entry seems to have no dependents.\n"); - ret = -ENODEV; - goto err_free_int3472; + "INT3472 seems to have no dependents.\n"); + return -ENODEV; } - int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(int3472->sensor)); - int3472->gpios.dev_id = int3472->sensor_name; + get_device(&int3472->sensor->dev); + + int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, + acpi_dev_name(int3472->sensor)); ret = skl_int3472_parse_crs(int3472); if (ret) { skl_int3472_discrete_remove(pdev); - goto err_return_ret; + return ret; } return 0; - -err_free_int3472: - kfree(int3472); -err_return_ret: - return ret; } int skl_int3472_discrete_remove(struct platform_device *pdev) { - struct int3472_device *int3472; - - int3472 = platform_get_drvdata(pdev); + struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev); - if (int3472->gpios_mapped) + if (int3472->gpios.dev_id) gpiod_remove_lookup_table(&int3472->gpios); - if (!IS_ERR_OR_NULL(int3472->regulator.rdev)) { - gpiod_put(int3472->regulator.gpio); + if (!IS_ERR(int3472->regulator.rdev)) regulator_unregister(int3472->regulator.rdev); - } - if (!IS_ERR_OR_NULL(int3472->clock.clk)) { - gpiod_put(int3472->clock.gpio); + if (!IS_ERR(int3472->clock.clk)) clk_unregister(int3472->clock.clk); + + if (int3472->clock.cl) clkdev_drop(int3472->clock.cl); - } + + if (!IS_ERR(int3472->regulator.gpio)) + gpiod_put(int3472->regulator.gpio); + + if (!IS_ERR(int3472->clock.ena_gpio)) + gpiod_put(int3472->clock.ena_gpio); + + if (!IS_ERR(int3472->clock.led_gpio)) + gpiod_put(int3472->clock.led_gpio); acpi_dev_put(int3472->sensor); diff --git a/drivers/platform/x86/intel_skl_int3472_tps68470.c b/drivers/platform/x86/intel-int3472/intel_skl_int3472_tps68470.c similarity index 53% rename from drivers/platform/x86/intel_skl_int3472_tps68470.c rename to drivers/platform/x86/intel-int3472/intel_skl_int3472_tps68470.c index 40629291b3396..d0d2391e263fc 100644 --- a/drivers/platform/x86/intel_skl_int3472_tps68470.c +++ b/drivers/platform/x86/intel-int3472/intel_skl_int3472_tps68470.c @@ -2,12 +2,24 @@ /* Author: Dan Scally */ #include +#include #include #include #include #include "intel_skl_int3472_common.h" +static const struct mfd_cell tps68470_c[] = { + { .name = "tps68470-gpio" }, + { .name = "tps68470_pmic_opregion" }, +}; + +static const struct mfd_cell tps68470_w[] = { + { .name = "tps68470-gpio" }, + { .name = "tps68470-clk" }, + { .name = "tps68470-regulator"}, +}; + static const struct regmap_config tps68470_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -30,49 +42,22 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) return ret; } - dev_info(dev, "TPS68470 REVID: 0x%x\n", version); + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); return 0; } -static struct platform_device * -skl_int3472_register_pdev(const char *name, struct device *parent) -{ - struct platform_device *pdev; - int ret; - - pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); - if (IS_ERR_OR_NULL(pdev)) - return ERR_PTR(-ENOMEM); - - pdev->dev.parent = parent; - pdev->driver_override = kstrndup(pdev->name, INT3472_PDEV_MAX_NAME_LEN, - GFP_KERNEL); - - ret = platform_device_add(pdev); - if (ret) { - platform_device_put(pdev); - return ERR_PTR(ret); - } - - return pdev; -} - int skl_int3472_tps68470_probe(struct i2c_client *client) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); - struct platform_device *regulator_dev; - struct platform_device *opregion_dev; - struct platform_device *gpio_dev; struct int3472_cldb cldb = { 0 }; - struct platform_device *clk_dev; bool cldb_present = true; struct regmap *regmap; - int ret = 0; + int ret; regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "devm_regmap_init_i2c Error %ld\n", + dev_err(&client->dev, "Failed to create regmap: %ld\n", PTR_ERR(regmap)); return PTR_ERR(regmap); } @@ -81,7 +66,7 @@ int skl_int3472_tps68470_probe(struct i2c_client *client) ret = tps68470_chip_init(&client->dev, regmap); if (ret < 0) { - dev_err(&client->dev, "TPS68470 Init Error %d\n", ret); + dev_err(&client->dev, "TPS68470 init error %d\n", ret); return ret; } @@ -98,48 +83,31 @@ int skl_int3472_tps68470_probe(struct i2c_client *client) * Clock and Regulator drivers to bind to. * * 3. Any other value in control_logic_type, we should never have - * gotten to this point; crash and burn. + * gotten to this point; fail probe and return. */ ret = skl_int3472_fill_cldb(adev, &cldb); - if (!ret && cldb.control_logic_type != 2) + if (!ret && cldb.control_logic_type != 2) { + dev_err(&client->dev, "Unsupported control logic type %u\n", + cldb.control_logic_type); return -EINVAL; + } if (ret) cldb_present = false; - gpio_dev = skl_int3472_register_pdev("tps68470-gpio", &client->dev); - if (IS_ERR(gpio_dev)) - return PTR_ERR(gpio_dev); - - if (cldb_present) { - clk_dev = skl_int3472_register_pdev("tps68470-clk", - &client->dev); - if (IS_ERR(clk_dev)) { - ret = PTR_ERR(clk_dev); - goto err_free_gpio; - } - - regulator_dev = skl_int3472_register_pdev("tps68470-regulator", - &client->dev); - if (IS_ERR(regulator_dev)) { - ret = PTR_ERR(regulator_dev); - goto err_free_clk; - } - } else { - opregion_dev = skl_int3472_register_pdev("tps68470_pmic_opregion", - &client->dev); - if (IS_ERR(opregion_dev)) { - ret = PTR_ERR(opregion_dev); - goto err_free_gpio; - } + if (cldb_present) + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + tps68470_w, ARRAY_SIZE(tps68470_w), + NULL, 0, NULL); + else + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + tps68470_c, ARRAY_SIZE(tps68470_c), + NULL, 0, NULL); + + if (ret) { + dev_err(&client->dev, "Failed to add MFD devices\n"); + return ret; } return 0; - -err_free_clk: - platform_device_put(clk_dev); -err_free_gpio: - platform_device_put(gpio_dev); - - return ret; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 33deb22294f27..5b14a9ae4ed56 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -278,6 +278,12 @@ struct acpi_device_power { struct acpi_device_power_state states[ACPI_D_STATE_COUNT]; /* Power states (D0-D3Cold) */ }; +struct acpi_dep_data { + struct list_head node; + acpi_handle supplier; + acpi_handle consumer; +}; + /* Performance Management */ struct acpi_device_perf_flags { @@ -683,8 +689,8 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev) bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2); -struct acpi_device * -acpi_dev_get_next_dep_dev(struct acpi_device *adev, struct acpi_device *prev); +void acpi_dev_flag_dependency_met(acpi_handle handle); +struct acpi_device *acpi_dev_get_dependent_dev(struct acpi_device *supplier); struct acpi_device * acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv); struct acpi_device * diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 626d43b00c4fe..5f9048931258d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -655,7 +655,9 @@ extern bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv); int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); int acpi_device_modalias(struct device *, char *, int); -void acpi_walk_dep_device_list(acpi_handle handle); +int acpi_walk_dep_device_list(acpi_handle handle, + int (*callback)(struct acpi_dep_data *, void *), + void *data); struct platform_device *acpi_create_platform_device(struct acpi_device *, struct property_entry *); @@ -1073,7 +1075,6 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, struct acpi_resource_gpio **agpio); int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index); -struct gpio_desc *acpi_get_gpiod(char *path, int pin); #else static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares, struct acpi_resource_gpio **agpio) @@ -1084,10 +1085,6 @@ static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { return -ENXIO; } -struct gpio_desc *acpi_get_gpiod(char *path, int pin) -{ - return NULL; -} #endif /* Device properties */ diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index ef49307611d21..6eee751f44dd5 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -690,6 +690,8 @@ int devm_acpi_dev_add_driver_gpios(struct device *dev, const struct acpi_gpio_mapping *gpios); void devm_acpi_dev_remove_driver_gpios(struct device *dev); +struct gpio_desc *acpi_get_gpiod(char *path, int pin, char *label); + #else /* CONFIG_GPIOLIB && CONFIG_ACPI */ struct acpi_device; @@ -708,6 +710,11 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev, } static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {} +struct gpio_desc *acpi_get_gpiod(char *path, int pin, char *label) +{ + return NULL; +} + #endif /* CONFIG_GPIOLIB && CONFIG_ACPI */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index b82aac05b17fa..4d40a4b468100 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -998,7 +998,6 @@ bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, u32 i2c_acpi_find_bus_speed(struct device *dev); struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, struct i2c_board_info *info); -char *i2c_acpi_dev_name(struct acpi_device *adev); struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle); #else static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, @@ -1015,10 +1014,6 @@ static inline struct i2c_client *i2c_acpi_new_device(struct device *dev, { return ERR_PTR(-ENODEV); } -static inline char *i2c_acpi_dev_name(struct acpi_device *adev) -{ - return NULL; -} static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) { return NULL;