#ifndef __MSM_ADC_H #define __MSM_ADC_H #include #define MSM_ADC_MAX_CHAN_STR 64 /* must be <= to the max buffer size in the modem implementation */ #define MSM_ADC_DEV_MAX_INFLIGHT 9 #define MSM_ADC_IOCTL_CODE 0x90 struct msm_adc_conversion { /* hwmon channel number - this is not equivalent to the DAL chan */ uint32_t chan; /* returned result in ms */ int result; }; struct adc_chan_result { /* The channel number of the requesting/requested conversion */ uint32_t chan; /* The pre-calibrated digital output of a given ADC relative to the ADC reference */ int32_t adc_code; /* in units specific for a given ADC; most ADC uses reference voltage * but some ADC uses reference current. This measurement here is * a number relative to a reference of a given ADC */ int64_t measurement; /* The data meaningful for each individual channel whether it is * voltage, current, temperature, etc. */ int64_t physical; }; /* * Issue a blocking adc conversion request. Once the call returns, the data * can be found in the 'physical' field of adc_chan_result. This call will * return ENODATA if there is an invalid result returned by the modem driver. */ #define MSM_ADC_REQUEST _IOWR(MSM_ADC_IOCTL_CODE, 1, \ struct adc_chan_result) /* * Issue a non-blocking adc conversion request. The results from this * request can be obtained by calling AIO_READ once the transfer is * completed. To verify completion, the blocking call AIO_POLL can be used. * If there are no slot resources, this call will return an error with errno * set to EWOULDBLOCK. */ #define MSM_ADC_AIO_REQUEST _IOWR(MSM_ADC_IOCTL_CODE, 2, \ struct adc_chan_result) /* * Same non-blocking semantics as AIO_REQUEST, except this call will block * if there are no available slot resources. This call can fail with errno * set to EDEADLK if there are no resources and the file descriptor in question * has outstanding conversion requests already. This is done so the client * does not block on resources that can only be freed by reading the results -- * effectively deadlocking the system. In this case, the client must read * pending results before proceeding to free up resources. */ #define MSM_ADC_AIO_REQUEST_BLOCK_RES _IOWR(MSM_ADC_IOCTL_CODE, 3, \ struct adc_chan_result) /* * Returns the number of pending results that are associated with a particular * file descriptor. If there are no pending results, this call will block until * there is at least one. If there are no requests queued at all on this file * descriptor, this call will fail with EDEADLK. This is to prevent deadlock in * a single-threaded scenario where POLL would never return. */ #define MSM_ADC_AIO_POLL _IOR(MSM_ADC_IOCTL_CODE, 4, \ uint32_t) #define MSM_ADC_FLUID_INIT _IOR(MSM_ADC_IOCTL_CODE, 5, \ uint32_t) #define MSM_ADC_FLUID_DEINIT _IOR(MSM_ADC_IOCTL_CODE, 6, \ uint32_t) struct msm_adc_aio_result { uint32_t chan; int result; }; /* * Read the results from an AIO / non-blocking conversion request. AIO_POLL * should be used before using this command to verify how many pending requests * are available for the file descriptor. This call will fail with errno set to * ENOMSG if there are no pending messages to be read at the time of the call. * The call will return ENODATA if there is an invalid result returned by the * modem driver. */ #define MSM_ADC_AIO_READ _IOR(MSM_ADC_IOCTL_CODE, 5, \ struct adc_chan_result) struct msm_adc_lookup { /* channel name (input) */ char name[MSM_ADC_MAX_CHAN_STR]; /* local channel index (output) */ uint32_t chan_idx; }; /* * Look up a channel name and get back an index that can be used * as a parameter to the conversion request commands. */ #define MSM_ADC_LOOKUP _IOWR(MSM_ADC_IOCTL_CODE, 6, \ struct msm_adc_lookup) #ifdef __KERNEL__ #define MSM_ADC_MAX_NUM_DEVS 3 enum { ADC_CONFIG_TYPE1, ADC_CONFIG_TYPE2, ADC_CONFIG_NONE = 0xffffffff }; enum { ADC_CALIB_CONFIG_TYPE1, ADC_CALIB_CONFIG_TYPE2, ADC_CALIB_CONFIG_TYPE3, ADC_CALIB_CONFIG_TYPE4, ADC_CALIB_CONFIG_TYPE5, ADC_CALIB_CONFIG_TYPE6, ADC_CALIB_CONFIG_TYPE7, ADC_CALIB_CONFIG_NONE = 0xffffffff }; enum { /* CHAN_PATH_TYPEn is specific for each ADC driver and can be used however way it wants*/ CHAN_PATH_TYPE1, CHAN_PATH_TYPE2, CHAN_PATH_TYPE3, CHAN_PATH_TYPE4, CHAN_PATH_TYPE5, CHAN_PATH_TYPE6, CHAN_PATH_TYPE7, CHAN_PATH_TYPE8, CHAN_PATH_TYPE9, CHAN_PATH_TYPE10, CHAN_PATH_TYPE11, CHAN_PATH_TYPE12, CHAN_PATH_TYPE13, CHAN_PATH_TYPE14, CHAN_PATH_TYPE15, CHAN_PATH_TYPE16, /* A given channel connects directly to the ADC */ CHAN_PATH_TYPE_NONE = 0xffffffff }; #define CHANNEL_ADC_BATT_ID 0 #define CHANNEL_ADC_BATT_THERM 1 #define CHANNEL_ADC_BATT_AMON 2 #define CHANNEL_ADC_VBATT 3 #define CHANNEL_ADC_VCOIN 4 #define CHANNEL_ADC_VCHG 5 #define CHANNEL_ADC_CHG_MONITOR 6 #define CHANNEL_ADC_VPH_PWR 7 #define CHANNEL_ADC_USB_VBUS 8 #define CHANNEL_ADC_DIE_TEMP 9 #define CHANNEL_ADC_DIE_TEMP_4K 0xa #define CHANNEL_ADC_XOTHERM 0xb #define CHANNEL_ADC_XOTHERM_4K 0xc #define CHANNEL_ADC_HDSET 0xd #define CHANNEL_ADC_MSM_THERM 0xe #define CHANNEL_ADC_625_REF 0xf #define CHANNEL_ADC_1250_REF 0x10 #define CHANNEL_ADC_325_REF 0x11 #define CHANNEL_ADC_FSM_THERM 0x12 #define CHANNEL_ADC_PA_THERM 0x13 enum { CALIB_STARTED, CALIB_NOT_REQUIRED = 0xffffffff, }; struct linear_graph { int32_t offset; int32_t dy; /* Slope numerator */ int32_t dx; /* Slope denominator */ }; struct adc_map_pt { int32_t x; int32_t y; }; struct adc_properties { uint32_t adc_reference; /* milli-voltage for this adc */ uint32_t bitresolution; bool bipolar; uint32_t conversiontime; }; struct chan_properties { uint32_t gain_numerator; uint32_t gain_denominator; struct linear_graph *adc_graph; /* this maybe the same as adc_properties.ConversionTime if channel does not change the adc properties */ uint32_t chan_conv_time; }; struct msm_adc_channels { char *name; uint32_t channel_name; uint32_t adc_dev_instance; struct adc_access_fn *adc_access_fn; uint32_t chan_path_type; uint32_t adc_config_type; uint32_t adc_calib_type; int32_t (*chan_processor)(int32_t, const struct adc_properties *, const struct chan_properties *, struct adc_chan_result *); }; struct msm_adc_platform_data { struct msm_adc_channels *channel; uint32_t num_chan_supported; uint32_t num_adc; uint32_t chan_per_adc; char **dev_names; uint32_t target_hw; uint32_t gpio_config; u32 (*adc_gpio_enable) (int); u32 (*adc_gpio_disable) (int); u32 (*adc_fluid_enable) (void); u32 (*adc_fluid_disable) (void); }; enum hw_type { MSM_7x30, MSM_8x60, FSM_9xxx, MSM_8x25, }; enum epm_gpio_config { MPROC_CONFIG, APROC_CONFIG }; enum adc_request { START_OF_CONV, END_OF_CONV, START_OF_CALIBRATION, END_OF_CALIBRATION, }; struct adc_dev_spec { uint32_t hwmon_dev_idx; struct dal_dev_spec { uint32_t dev_idx; uint32_t chan_idx; } dal; }; struct dal_conv_request { struct dal_dev_spec target; void *cb_h; }; struct dal_adc_result { uint32_t status; uint32_t token; uint32_t dev_idx; uint32_t chan_idx; int physical; uint32_t percent; uint32_t microvolts; uint32_t reserved; }; struct dal_conv_slot { void *cb_h; struct dal_adc_result result; struct completion comp; struct list_head list; uint32_t idx; uint32_t chan_idx; bool blocking; struct msm_client_data *client; }; struct dal_translation { uint32_t dal_dev_idx; uint32_t hwmon_dev_idx; uint32_t hwmon_start; uint32_t hwmon_end; }; struct msm_client_data { struct list_head complete_list; bool online; int32_t adc_chan; uint32_t num_complete; uint32_t num_outstanding; wait_queue_head_t data_wait; wait_queue_head_t outst_wait; struct mutex lock; }; struct adc_conv_slot { void *cb_h; union { struct adc_chan_result result; struct dal_adc_result dal_result; } conv; struct completion comp; struct completion *compk; struct list_head list; uint32_t idx; enum adc_request adc_request; bool blocking; struct msm_client_data *client; struct work_struct work; struct chan_properties chan_properties; uint32_t chan_path; uint32_t chan_adc_config; uint32_t chan_adc_calib; }; struct adc_access_fn { int32_t (*adc_select_chan_and_start_conv)(uint32_t, struct adc_conv_slot*); int32_t (*adc_read_adc_code)(uint32_t dev_instance, int32_t *data); struct adc_properties *(*adc_get_properties)(uint32_t dev_instance); void (*adc_slot_request)(uint32_t dev_instance, struct adc_conv_slot **); void (*adc_restore_slot)(uint32_t dev_instance, struct adc_conv_slot *slot); int32_t (*adc_calibrate)(uint32_t dev_instance, struct adc_conv_slot*, int *); }; void msm_adc_wq_work(struct work_struct *work); void msm_adc_conv_cb(void *context, u32 param, void *evt_buf, u32 len); #ifdef CONFIG_SENSORS_MSM_ADC int32_t adc_channel_open(uint32_t channel, void **h); int32_t adc_channel_close(void *h); int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt); int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result); #else static inline int32_t adc_channel_open(uint32_t channel, void **h) { pr_err("%s.not supported.\n", __func__); return -ENODEV; } static inline int32_t adc_channel_close(void *h) { pr_err("%s.not supported.\n", __func__); return -ENODEV; } static inline int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt) { pr_err("%s.not supported.\n", __func__); return -ENODEV; } static inline int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result) { pr_err("%s.not supported.\n", __func__); return -ENODEV; } #endif /* CONFIG_SENSORS_MSM_ADC */ #endif #endif /* __MSM_ADC_H */